1. 程式人生 > 其它 >洛谷P6883 [COCI2016-2017#3] Kroničan 題解 狀壓DP入門題

洛谷P6883 [COCI2016-2017#3] Kroničan 題解 狀壓DP入門題

題目連結:https://www.luogu.com.cn/problem/P6883

解題思路:

對於每個狀態 \(s\),它的上一個狀態 \(s'\) 必然滿足:\(s'\) 的二進位制表示中恰好有一位和 \(s\) 不相同,且那一位為 \(1\)。(設這一位為第 \(i\) 位)

然後遍歷 \(s\) 的二進位制表示中所有為 \(1\) 的那些位(設為第 \(j\) 位)。

\(i \rightarrow j\) 可以看做一個狀態轉移。

\(f_{s}\) 為到達狀態 \(s\) 的最小代價總和,則 \(f_{s} = \max\{ f_{s'} + c_{i,j} \}\)

示例程式:

#include <bits/stdc++.h>
using namespace std;
int n, k, c[22][22], f[1<<20], ans = (1<<29);
int main() {
    cin >> n >> k;
    for (int i = 0; i < n; i ++)
        for (int j = 0; j < n; j ++)
            cin >> c[i][j];
    memset(f, 0x3f, sizeof(f));
    f[(1<<n)-1] = 0;
    for (int st = (1<<n)-2; st > 0; st --) {
        for (int i = 0; i < n; i ++) {
            if (!(st & (1<<i))) {
                int st2 = st ^ (1<<i);
                for (int j = 0; j < n; j ++) {
                    if (st & (1<<j)) {
                        f[st] = min(f[st], f[st2] + c[i][j]);
                    }
                }
            }
        }
    }
    for (int st = 0; st < (1<<n); st ++) {
        if (__builtin_popcount(st) == k) {
            ans = min(ans, f[st]);
        }
    }
    cout << ans << endl;
    return 0;
}