C++で要素を有効に塗り分けるための最小色数を求めるコード解説
n 個の要素を持つ配列 A があるとします。この配列の要素を、次の条件を満たすように色で塗り分けることを考えます。
- どの色を選んでも、その色で塗られたすべての要素は、同じ色グループ内の最小値で割り切れること。
- 使用する色の数はできるだけ少なくすること。
与えられたすべての数を有効な方法で塗り分けるために必要な、最小の色の数を求めるのがこの問題です。
例えば、入力が A = [10, 2, 3, 5, 4, 2] の場合、出力は 3 になります。1 番目の色で A[0] と A[3] を塗り、2 番目の色で A[2] を塗り、残りの 3 つの要素を 3 番目の色で塗ればよいからです。
解法のアプローチ
この問題を解くには、以下の手順に従います。
- まず配列 A を昇順にソートします。
- 各要素について、それより前にある(小さい)要素で割り切れるかどうかを確認します。
- どの先行要素でも割り切れない場合、その要素は新しい色グループの最小値になる必要があるため、色を 1 つ増やします。
このアルゴリズムが正しく動作する理由は、ソート後の配列において、ある要素がそれより小さいいずれかの要素で割り切れるなら、その要素の色グループに追加できるためです。逆に、どの先行要素でも割り切れない要素は、必ず自身が属するグループの最小値にならざるを得ません。計算量は二重ループにより O(n²) となります。
アルゴリズムの擬似コード
n := A のサイズ
ans := 0
配列 A をソートする
i := 0 から i < n まで、i を 1 ずつ増やしながら繰り返す:
ok := 1
j := 0 から j < i まで、j を 1 ずつ増やしながら繰り返す:
ok := ok AND (A[i] mod A[j] が 0 でなければ 1、そうでなければ 0)
ans := ans + ok
ans を返すC++ 実装例
理解を深めるために、実際の C++ コードを見てみましょう。
#include <bits/stdc++.h>
using namespace std;
int solve(vector<int> A)
{
int n = A.size();
int ans = 0;
sort(A.begin(), A.end());
for (int i = 0; i < n; i++)
{
int ok = 1;
for (int j = 0; j < i; j++)
ok &= (A[i] % A[j] != 0);
ans += ok;
}
return ans;
}
int main()
{
vector<int> A = { 10, 2, 3, 5, 4, 2 };
cout << solve(A) << endl;
}入力
{ 10, 2, 3, 5, 4, 2 }出力
3
-
ロボットが最終位置に到達するまでの最小ステップ数を求めるC++プログラム
2つの座標 (x1, y1) と (x2, y2) があるとします。ロボットは現在点 (x1, y1) にいて、点 (x2, y2) へ移動したいと考えています。ロボットは1ステップごとに、周囲8方向(上下左右と斜め)の隣接するマスのいずれかに移動することができます。このとき、最終位置に到達するために必要な最小ステップ数を求めます。 例えば、入力が x1 = 3; y1 = 4; x2 = 6; y2 = 1; の場合、出力は 3 になります。その様子は以下の図の通りです。 解き方 この問題を解くには、次のステップに従います。 return max(|x2 - x1|, |y2 - y1|
-
C++で平面内に形成できる平行四辺形の数を数えるアルゴリズム
本記事の課題は、平面上に与えられた点集合から形成できる平行四辺形の個数を求めることです。平行四辺形とは、四角形の対辺が互いに平行であり、それに伴って対角も等しくなる四角形のことを指します。 入力 − int a[] = {0, 2, 5, 5, 2, 5, 2, 5, 2} int b[] = {0, 0, 1, 4, 3, 8, 7, 11, 10} 出力 − 平面内の平行四辺形の数 − 3 説明 − (x, y) 座標の点が与えられており、これらの点を組み合わせると、図のように 3 つの平行四辺形を形成できます。 入力 − a[] = {0, 3, 1, 4, 1, 5} b[] =