0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AtCoder Educational DP Contest U問題解いてみた

Posted at

AtCoder Educational DP Contest U問題解いてみた

今回の問題

問題文

$N$ 羽のうさぎたちがいます。 うさぎたちには $1, 2, \ldots, N$ と番号が振られています。
各 $i, j$ ($1 \leq i, j \leq N$) について、うさぎ $i$ と $j$ の相性が整数 $a_{i,j}$ によって与えられます。
ただし、各 $i$ ($1 \leq i \leq N$) について $a_{i,i} = 0$ であり、各 $i, j$ ($1 \leq i, j \leq N$) について $a_{i,j} = a_{j,i}$ です。

太郎君は、$N$ 羽のうさぎたちをいくつかのグループへ分けようとしています。
このとき、各うさぎはちょうど $1$ つのグループに属さなければなりません。

グループ分けの結果、各 $i, j$ ($1 \leq i < j \leq N$) について、うさぎ $i$ と $j$ が同じグループに属するならば、太郎君は $a_{i,j}$ 点を得ます。
太郎君の総得点の最大値を求めてください。

制約

  • 入力はすべて整数である。
  • $1 \leq N \leq 16$
  • $|a_{i,j}| \leq 10^9$
  • $a_{i,i} = 0$
  • $a_{i,j} = a_{j,i}$

回答

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

int main() {
    int N;
    cin >> N;

    // 行列入力
    vector<vector<long long>> a(N, vector<long long>(N));
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            cin >> a[i][j];
        }
    }

    // 前計算: score[S]
    // 集合 S を「1つのグループ」にしたときのスコア合計
    vector<long long> score(1 << N, 0);
    for (int S = 0; S < (1 << N); S++) {
        for (int i = 0; i < N; i++) {
            for (int j = i + 1; j < N; j++) {
                // i も j も S に含まれているなら加算
                if ((S & (1 << i)) && (S & (1 << j))) {
                    score[S] += a[i][j];
                }
            }
        }
    }

    // dp[S] := 集合 S を最適にグループ分けしたときの最大スコア
    vector<long long> dp(1 << N, 0);

    // 小さい集合から順に計算
    for (int S = 0; S < (1 << N); S++) {
        // 部分集合 T を列挙する定石テクニック
        // T = S から始めて、T = (T - 1) & S で更新すると、Sの部分集合のみを降順に走査できる
        // T = 0 になったら終了
        for (int T = S; T > 0; T = (T - 1) & S) {
            // 遷移: S の一部 T を「1グループ」として切り出し、
            // 残り (S ^ T) は計算済みの dp を使う
            dp[S] = max(dp[S], score[T] + dp[S ^ T]);
        }
    }

    // 全員 (mask = (1<<N)-1) のときの最大値
    cout << dp[(1 << N) - 1] << endl;

    return 0;
}

自分なりの解説

DPの遷移:dp[S] = 「集合$S$のうさぎたちを、最適なグループ分けにしたときの最大スコア」とする。Sが小さいので個々の全列挙は可能である。元の集合を集合 $S$ を、「ある1つのグループ $T$ 」と「残りのうさぎたちに分割することを考える。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?