C++で軸の片側に点を集めるために削除すべき点の最小数を求める方法
問題の概要
デカルト平面上に N 個の点が与えられます。いくつかの点を削除して、残ったすべての点が「任意のひとつの軸の片側」に収まるようにしたいとき、削除が必要な点の数の最小値を求めるのが本問題の目的です。
たとえば、入力が {(10, 5), (-2, -5), (13, 8), (-14, 7)} だったとします。ここで (-2, -5) を削除すれば、残りの点はすべて X 軸より上側に位置することになります。
したがって、この場合の答えは 1 となります。
アルゴリズム
考え方はとてもシンプルです。点を軸の片側に集めたいなら、「反対側にある点をすべて取り除けばよい」からです。具体的には次の手順で解きます。
- X 軸の上下、Y 軸の左右、それぞれの領域に存在する点の数を数えます。
- 数えた 4 つの値のうち、最も小さいものを答えとして返します。
各点の座標を一度だけ走査すればよいため、計算量は O(N) と非常に効率的です。
C++ による実装例
#include <iostream>
#include <algorithm>
#define SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
using namespace std;
struct point{
int x, y;
};
int minPointsToBeRemoved(point arr[], int n){
int a = 0, b = 0, c = 0, d = 0;
for (int i = 0; i < n; i++){
if (arr[i].x >= 0)
b++;
else if (arr[i].x <= 0)
a++;
if (arr[i].y <= 0)
d++;
else if (arr[i].y >= 0)
c++;
}
return min({a, d, c, b});
}
int main(){
point arr[] = {{10, 5}, {-2, -5}, {13, 8}, {-14, 7}};
cout << "Minimum points to be removed = " <<
minPointsToBeRemoved(arr, SIZE(arr)) << endl;
return 0;
}コード内の変数は、それぞれ次の領域の点数を表しています。
- a: X 座標が負の点(Y 軸の左側)の数
- b: X 座標が 0 以上の点(Y 軸の右側)の数
- c: Y 座標が正の点(X 軸の上側)の数
- d: Y 座標が 0 以下の点(X 軸の下側)の数
これら 4 つの値の最小値を min({a, d, c, b}) で返すことで、削除すべき点の最小数が求まります。
実行結果
上記のプログラムをコンパイルして実行すると、次の出力が得られます。
Minimum points to be removed = 1
-
【C++】文字列を別の文字列へ変換するために必要な最小の削除・挿入回数を求める方法
問題の概要大きさがそれぞれ m と n の2つの文字列 str1 と str2 が与えられたとします。ここで求めたいのは、str1 を str2 に変換するために必要な「削除」と「挿入」の操作回数を最小化するという課題です。例として、次のようなケースを考えてみましょう。Str1 = tutorialspoint Str2 = tutorials str1 を str2 に変換するには、5文字分の削除、つまり str1 から point を取り除く必要があります。解法の考え方:最長共通部分列(LCS)この問題は、最長共通部分列(Longest Common Subsequence:LCS) を利
-
【C++】素因数分解で約数の和の最小値を求めるアルゴリズムを解説
約数の和の最小値を求める問題とは この記事では、与えられた整数の「約数の和の最小値」を求めるアルゴリズムを、C++で実装しながら解説します。 例として、数12を考えてみましょう。12は以下のように複数の方法で因数分解できます。 12 = 12 × 1 → 和は 12 + 1 = 13 12 = 2 × 6 → 和は 2 + 6 = 8 12 = 3 × 4 → 和は 3 + 4 = 7 12 = 2 × 2 × 3 → 和は 2 + 2 + 3 = 7 この中で最小となる和は7です。本記事では、任意の整数nが与えられたとき、この最小の和を効率よく求める方法を紹介します。 アプローチ:素因数