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

C++で合計が等しい2つの集合の最大合計を求めるプログラム

問題概要

数値のリスト nums が与えられます。このリストの要素を振り分けて合計が等しくなる2つの集合を作成し、そのときの合計値の最大を求めます。

たとえば、入力が nums = [2, 5, 4, 6] の場合、出力は 6 になります。[2, 4][6] という2つの集合を作れば、どちらも合計が 6 となり、これより大きい等しい合計は実現できないためです。

解決アプローチ(動的計画法)

各要素には「集合Aに入れる」「集合Bに入れる」「どちらにも入れない」という3つの選択肢があります。素朴な全探索では O(3^n) の計算量が必要になりますが、2つの集合の合計の差分を状態として管理する動的計画法(DP)を用いれば、効率的に解くことができます。

DPテーブル dp[i][j] は、「先頭から i 個の要素を処理したとき、2つの集合の合計差が j - sum となる状態における、片方の集合の合計の最大値」を表します。到達できない状態は -1 で表し、初期状態は dp[0][sum] = 0(差分ゼロ・合計ゼロ)とします。

アルゴリズムの手順

  • sum := 0 とし、nums の各要素 i について sum := sum + i を実行する(総和を計算)
  • n := nums のサイズ
  • サイズ (n + 1) × (2 * sum + 5) の2次元配列 dp を定義し、すべて -1 で埋める
  • dp[0][sum] := 0 とする
  • i を 1 から n まで 1 ずつ増やしながら繰り返す:
    • x := nums[i - 1]
    • j を 0 から 2 * sum + 5 未満まで 1 ずつ増やしながら繰り返す:
      • j - x >= 0 かつ dp[i - 1][j - x] != -1 の場合:
        dp[i][j] := max(dp[i][j], dp[i - 1][j - x] + x)(要素 x を合計の大きい側の集合に追加)
      • j + x < 2 * sum + 5 かつ dp[i - 1][j + x] != -1 の場合:
        dp[i][j] := max(dp[i][j], dp[i - 1][j + x])(要素 x をもう一方の集合に追加)
      • dp[i][j] := max(dp[i][j], dp[i - 1][j])(要素 x を使用しない)
  • dp[n][sum] を返す(合計差がゼロ、つまり2つの集合の合計が等しいときの最大値)

C++の実装例

理解を深めるために、以下の実装を見てみましょう。

#include <bits/stdc++.h>
using namespace std;
class Solution {
   public:
   int solve(vector<int>& nums) {
      int sum = 0;
      for (int i : nums) sum += i;
      int n = nums.size();
      vector<vector<int> > dp(n + 1, vector<int>(2 * sum + 5, -1));
      dp[0][sum] = 0;
      for (int i = 1; i <= n; i++) {
         int x = nums[i - 1];
         for (int j = 0; j < 2 * sum + 5; j++) {
            if (j - x >= 0 && dp[i - 1][j - x] != -1) {
               dp[i][j] = max(dp[i][j], dp[i - 1][j - x] + x);
            }
            if (j + x < 2 * sum + 5 && dp[i - 1][j + x] != -1) {
               dp[i][j] = max(dp[i][j], dp[i - 1][j + x]);
            }
            dp[i][j] = max(dp[i][j], dp[i - 1][j]);
         }
      }
      return dp[n][sum];
   }
};
int solve(vector<int>& nums) {
   return (new Solution())->solve(nums);
}
main(){
   vector<int> v = {2, 5, 4, 6};
   cout << solve(v);
}

入力

{2, 5, 4, 6}

出力

6

計算量の目安

  • 時間計算量: O(n × sum) — 各要素ごとに差分の状態全体を走査します。
  • 空間計算量: O(n × sum) — DPテーブルの保存に必要なメモリ量です。
  1. C++で2つの数値を加算するプログラムの書き方【サンプルコード付き】

    加算(足し算)は、最も基本的な算術演算の一つです。2つの数値を加算するプログラムは、指定された2つの数値の合計を計算し、その結果を画面に表示します。この記事では、C++で2つの数値を加算する方法を、変数を使った基本例と配列を使った応用例の2パターンに分けて解説します。例1:変数を使って2つの数値を加算するまずは、最もシンプルな方法です。2つの整数型変数を用意し、その合計を別の変数に格納して出力します。#include <iostream> using namespace std; int main() { int num1 = 15, num2 = 10, sum;

  2. Pythonで長さxとyの重ならない2つのサブリストの最大合計を求める方法

    問題概要 数値のリスト nums と整数 x、y が与えられたとき、それぞれ長さが x と y であり、互いに重なり合わない2つのサブリスト(部分リスト)を選び、その要素の合計の最大値を求めるのが今回の課題です。 たとえば、nums = [3, 2, 10, -2, 7, 6]、x = 3、y = 1 という入力の場合、出力は 22 になります。これは、長さ3のサブリストとして [3, 2, 10] を、もう一方として [7] を選んだ場合の合計(15 + 7 = 22)に該当します。 解法のアプローチ:累積和(Prefix Sum)を活用 この問題は、累積和を使うことで線形時間 O(n) で