C++で配列の全要素を削除するために必要な最小操作数を求める方法
問題の概要
整数型の配列 arr が与えられたとき、配列のすべての要素を削除するために必要な最小の操作数を求めるのが課題です。ただし、要素を削除する際には次の制約が課されます。
- 配列から任意の要素を自由に選択でき、その要素で割り切れるすべての要素を一度に配列から削除できる。
例えば、arr[] = {2, 4, 15, 10, 8, 5, 3} の場合、すべての要素を削除するには3回の操作が必要です。
- 2 を選択すると、{2, 4, 10, 8} が削除されます。
- 5 を選択すると、{5, 15} が削除されます。
- 3 を選択すると、{3} が削除されます。
アルゴリズム
- 配列を昇順にソートし、各要素の出現回数をカウントします。
- 先頭から順に未処理の要素を調べ、その要素で割り切れるすべての要素を削除済みとしてマークし、結果カウンターを1増やします。
解法のポイント
この問題は貪欲法で効率的に解くことができます。配列をあらかじめ昇順にソートしておけば、選んだ要素の倍数は必ず配列の後ろ側に存在します。そのため、各操作で「まだ削除されていない最小の要素」を選ぶことで、その倍数をまとめて削除でき、操作回数を最小限に抑えられます。
実装例(C++)
#include <iostream>
#include <algorithm>
#define SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
#define MAX 100
using namespace std;
int getMinOperations(int *arr, int n){
int map[MAX] = {0};
sort(arr, arr + n);
for (int i = 0; i < n; ++i) {
map[arr[i]]++;
}
int cnt = 0;
for (int i = 0; i < n; ++i) {
if (map[arr[i]]) {
for (int j = i; j < n; ++j) {
if (arr[j] % arr[i] == 0) {
map[arr[j]] = 0;
}
}
++cnt;
}
}
return cnt;
}
int main(){
int arr[] = {2, 4, 15, 10, 8, 5, 3};
cout << "Minimum required operations = " << getMinOperations(arr, SIZE(arr)) << endl;
return 0;
}出力
上記のプログラムをコンパイルして実行すると、次の出力が得られます。
Minimum required operations = 3
-
C++ですべての要素を割り切れる配列の要素を見つける方法
いくつかの要素を持つ配列 A があるとします。この中から「他のすべての要素を割り切ることができる」1つの要素を見つけたいと思います。例として、配列 A = [15, 21, 69, 33, 3, 72, 81] を考えてみましょう。この場合、答えは 3 になります。リスト内のすべての数値が3で割り切れるためです。解決策のアプローチこの問題は、以下の手順でシンプルに解くことができます。まず、配列内の最小値を求めます。次に、すべての要素がその最小値で割り切れるかどうかを確認します。すべて割り切れれば、その最小値を返します。1つでも割り切れない要素があれば、-1 を返します(条件を満たす要素は存在し
-
C++で配列の全要素を同じ値にするための最小削除操作数を求めるアルゴリズム
問題概要n個の要素からなる配列が与えられます。要素には重複が含まれる場合があります。この配列から任意の数の要素を削除できるとき、すべての要素を同じ値にするために必要な最小の削除数を求めるのが課題です。例として、次の配列を考えてみましょう。arr[] = {10, 8, 10, 7, 10, -1, -4, 12}この場合、最も多く出現している「10」以外の5つの要素を削除すれば、配列の全要素を10で統一できます。つまり、答えは5回の削除となります。解法の考え方この問題の鍵となるのは、「削除する量を最小化する = 残す要素の数を最大化する」という発想です。全要素を同じ値にするためには、必ずどれか