C++
 Computer >> コンピューター >  >> プログラミング >> C++

C++でXORの合計値の最大値を求めるプログラム(貪欲法による解説)

問題概要

N個の要素を持つ配列 A と、ある整数 K が与えられます。0 以上 K 以下の範囲にある整数 X に対して、次のような関数 f(X) を定義します。

f(X) = (X XOR A[1]) + (X XOR A[2]) + ... + (X XOR A[N])

このとき、f(X) が取り得る最大値を求めるのがこの問題の目的です。

たとえば、入力が K = 7A = [1, 6, 3] の場合を考えてみましょう。X = 4 を選ぶと、
f(4) = (4 XOR 1) + (4 XOR 6) + (4 XOR 3) = 5 + 2 + 7 = 14
となり、これが最大値となります。

解き方(アルゴリズム)

この問題は、各ビット位置に着目した貪欲法(グリーディ法)で効率的に解くことができます。上位ビットから順に処理しながら、X の各ビットを 1 にすべきかどうかを判定し、合計値を最大化していきます。

具体的には、以下の手順に従います。

  1. 配列 A のサイズを n とします。
  2. i = 45 から 0 まで、ビット位置を降順に処理します。
  3. p = 2^i として、配列内でそのビットが立っている要素の個数 m を数えます。
  4. これまでに確定した X の値 o に p を加えても K を超えない場合は、X の該当ビットを 1 にできるか検討します。ビットを立てたほうが合計が大きくなる(m < n - m の場合)なら、X のビットを立てます。
  5. 各ビットの寄与分 p × m を答え d に加算していきます。
n := size of A
for initialize i := 45, when i >= 0, update (decrease i by 1), do:
   p := 2^i
   m := 0
   for initialize j := 0, when j < n, update (increase j by 1), do:
      if A[j] AND p is non-zero, then:
         (increase m by 1)
   if o + p <= k, then:
      if m < n - m, then:
         m := n - m
         o := o + p
   d := d + p * m
return d

C++実装例

理解を深めるために、実際のC++コードを見てみましょう。

#include <bits/stdc++.h>
using namespace std;

long solve(int k, vector<int> A){
   long n = A.size(), d = 0, m, p, o = 0;
   for (long i = 45; i >= 0; i--){
      p = pow(2, i);
      m = 0;
      for (int j = 0; j < n; j++){
         if (A[j] & p)
            m++;
      }
      if (o + p <= k){
         if (m < n - m){
            m = n - m;
            o += p;
         }
      }
      d += p * m;
   }
   return d;
}
int main(){
   int K = 7;
   vector<int> A = { 1, 6, 3 };
   cout << solve(K, A) << endl;
}

入力

7, { 1, 6, 3 }

出力

14

まとめ

XORの性質を利用すると、各ビットを独立に評価できるため、ビット数 × N の計算量で最大値を求められます。XORを含む最適化問題では、ビット単位の貪欲法が有効なケースが多いため、考え方を覚えておくと競技プログラミングなどで役立ちます。

  1. C++で二分木の最大レベル和を求める方法

    問題概要 この問題では、正と負の値を含む二分木が与えられます。私たちのタスクは、二分木におけるレベル和の最大値を見つけることです。 問題の説明: 与えられた二分木に対して、各レベルに存在するすべてのノードの値の合計を計算し、その中で最も大きい値を返します。 具体例を使って問題を理解しましょう。 入力: 出力: 5 説明: レベル1の要素の合計:3 レベル2の要素の合計:-3 + 4 = 1 レベル3の要素の合計:5 - 1 + 6 - 5 = 5 各レベルの合計は「3」「1」「5」となるため、最大のレベル和は 5 となります。 解法アプローチ この問題を効率的に解くには、レベル順走査(幅優先

  2. Pythonで最小グループの合計が最大になるようリストをk個に分割する方法

    問題概要数値のリスト nums と整数 k が与えられたとします。このリストを「連続する要素からなる」k個のグループに分割することを考えます。ここで「最小グループ」とは、各グループの合計値の中で最も小さいものを持つグループのことです。求めたいのは、その最小グループの合計値が取りうる最大値です。例として、nums = [2, 6, 4, 5, 8]、k = 3 の場合を見てみましょう。リストを [2, 6]、[4, 5]、[8] の3つのグループに分割すると、それぞれの合計は 8、9、8 となり、最小グループの合計は 8 になります。どのように分割しても最小グループの合計が 8 を超えることはで