【C++】-1と+1からなる配列に、合計が0となるサイズKの部分集合が存在するか判定する方法
この問題では、1と-1のみから構成される配列 arr[] と整数値 k が与えられます。私たちのタスクは、-1と+1からなる配列の中に、合計が0となるサイズKの部分集合が存在するかどうかを判定することです。
問題例で理解しよう
入力: arr[] = {-1, 1, -1, -1, 1, 1, -1}, k = 4
出力: YES
説明:
サイズ4の部分集合 {-1, 1, -1, 1} を選ぶと、合計 = -1 + 1 - 1 + 1 = 0 となります。
解法の考え方
まず、合計が0になるサイズKの部分集合が存在するかどうかを確認する必要があります。部分集合には配列の任意の要素を選べるため、部分集合内に「1」と「-1」が同数含まれていれば、その合計は必ず0になります。
ここで重要なのは、1と-1を同数ずつ含むためには、部分集合のサイズKが偶数でなければならないという点です。さらに、実際に部分集合を組み立てられるかどうかは、配列全体に含まれる1の個数と-1の個数が、それぞれK/2個以上あるかどうかで決まります。
まとめると、以下の条件をすべて満たす場合に「YES」を返せます。
・Kが偶数である
・配列中の1の個数が K/2 以上である
・配列中の-1の個数が K/2 以上である
いずれかの条件でも満たさない場合は、条件を満たす部分集合は存在しません。
解法の実装プログラム
C++コード例
#include <iostream>
using namespace std;
// 配列内の1の個数を数える関数
int countOne(int a[], int n) {
int i, count = 0;
for (i = 0; i < n; i++)
if (a[i] == 1)
count++;
return count;
}
// 合計が0となるサイズKの部分集合が存在するか判定する関数
bool isSubSetSumZeroFound(int arr[], int n, int K) {
int totalOne = countOne(arr, n);
int totalNegOne = n - totalOne;
return (K % 2 == 0 && totalOne >= K / 2 && totalNegOne >= K / 2);
}
int main() {
int arr[] = { 1, 1, -1, -1, 1, -1, 1, 1, -1 };
int size = sizeof(arr) / sizeof(arr[0]);
int K = 4;
if (isSubSetSumZeroFound(arr, size, K))
cout<<"Subset of size "<<K<<" with sum of all elements 0 exists.";
else
cout<<"No subset found";
return 0;
}
実行結果
Subset of size 4 with sum of all elements 0 exists.
この出力は、「全要素の合計が0となるサイズ4の部分集合が存在する」ことを意味しています。
まとめ
本解法のポイントは、部分集合の合計が0になるためには1と-1が同数必要であることに着目し、Kの偶奇と各値の出現回数だけで判定できる点です。配列を一度走査するだけなので、時間計算量はO(n)、空間計算量はO(1)と非常に効率的です。
-
C++でGCDとLCMの値から条件を満たす数のペアの総数を求める方法
この記事では、最大公約数(GCD)と最小公倍数(LCM)の値が与えられたとき、その両方の条件を満たす整数のペアが全部で何通り存在するかを求める方法を解説します。 例として、GCDが2、LCMが12の場合を考えてみましょう。この条件を満たすペアは (2, 12)、(4, 6)、(6, 4)、(12, 2) の4つです。プログラムの目的は、このペアの総数「4」を計算することです。 解決の鍵となる数学的性質 2つの整数 a と b の間には、次のような重要な関係が常に成り立ちます。 a × b = GCD(a, b) × LCM(a, b) また、a と b はいずれも必ず GCD で割り切れるた
-
C/C++のlong型は本当に必要?サイズが環境によって異なる理由を解説
CおよびC++には、整数値を扱うためのデータ型としてshort、int、long、long longの4種類が用意されています。それぞれが占めるメモリ領域のサイズは異なり、さらにそのサイズはアーキテクチャやOS、コンパイラによって変化するという特徴を持っています。例えば、int型は環境によって4バイトになる場合もあれば、2バイトになる場合もあります。 クロスコンパイラとは何か こうしたサイズの違いを生む要因の一つが「クロスコンパイラ」の存在です。クロスコンパイラとは、現在実行中のプラットフォームとは別のプラットフォーム向けにコードをコンパイルできるコンパイラのことです。 そのため、まったく同