mayoko’s diary

プロコンとかいろいろ。

Codeforces Round #321 (Div. 2) D. Kefa and Dishes

起きれなかったので virtual participation で参加しました。ABCD 解けてそこそこです。ただ D 解くのが遅かったので反省です。

解法

dp[state][f] = (今までに選んだ食事が state で表されて, 一番先頭に選んでいる食事が f の時の, 最大幸福度)
として, bitDP を解けば良いです。

得た知見
  • 最初 state だけを状態として「どこに挿入するか」みたいなことをやろうとしていたが, よく考えると先頭に入れる順番を考えればよかったので上のような dp で良いんだなぁと
const int MAXN = 20;
const ll INF = 1ll<<55;
int n, m, k;
ll a[MAXN];
ll c[MAXN][MAXN];
ll dp[1<<MAXN][MAXN];

int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    cin >> n >> m >> k;
    for (int i = 0; i < n; i++) {
        cin >> a[i];
    }
    for (int i = 0; i < k; i++) {
        int x, y, z;
        cin >> x >> y >> z;
        x--; y--;
        c[x][y] = z;
    }
    memset(dp, -1, sizeof(dp));
    for (int i = 0; i < n; i++) {
        dp[1<<i][i] = a[i];
    }
    for (int s = 1; s < (1<<n); s++) {
        for (int i = 0; i < n; i++) {
            if (dp[s][i] == -1) continue;
            for (int j = 0; j < n; j++) {
                if ((s>>j)&1) continue;
                int ns = s|1<<j;
                dp[ns][j] = max(dp[ns][j], dp[s][i]+a[j]+c[j][i]);
            }
        }
    }
    ll ans = 0;
    for (int s = 0; s < (1<<n); s++) for (int i = 0; i < n; i++) {
        if (__builtin_popcount(s) == m) ans = max(ans, dp[s][i]);
    }
    cout << ans << endl;
    return 0;
}