CF580D Kefa and Dishes(状压DP)题解

思路

\(n \leq 18\),一看就很状压。

\(f_{st,i}\)为当前状态为\(st\)(二进制下第\(x\)位为\(1\)时表示选了第\(x\)个),最后一个选了\(i\)时的最大满意度(记录\(i\)是为了计算吃菜顺序的额外贡献),则有:

\[f_{st,i} = max(f_{pre,j} + a_i + c_{j,i}) \]

其中,\(j\)必须在状态\(st\)时被选中,\(pre\)\(st\)不选\(i\)时的状态。

至于统计答案,把\(st\)\(1\)的个数为\(m\)时的\(f\)\(min\)就可以了。

代码

#include <cstdio>
#include <algorithm>
#define LL long long

using namespace std;

const int maxn = 3e5 + 10;
int n,k,m;
LL a[20],c[20][20],f[maxn][20];

int cnt(int x){
    int num = 0;
    while(x) num += (x & 1), x >>= 1; 
    return num;
}

int main(){
    scanf("%d%d%d", &n, &m, &k);
    for(int i = 0; i < n; ++ i) scanf("%lld", &a[i]);
    for(int i = 1; i <= k; ++ i){
        int x,y; scanf("%d%d", &x, &y);
        scanf("%lld", &c[x - 1][y - 1]);
    } LL Ans = 0;
    for(int st = 0; st < (1 << n); ++ st){
        for(int i = 0; i < n; ++ i){
            bool flag = 0;
            if(st & (1 << i)){
                for(int j = 0; j < n; ++ j){
                    if(j == i || !(st & (1 << j))) continue;
                    flag = 1;
                    f[st][i] = max(f[st][i], f[st ^ (1 << i)][j] + a[i] + c[j][i]);
                }
                if(!flag) f[st][i] = a[i];
            }
            if(cnt(st) == m) Ans = max(Ans, f[st][i]);
        }
    }
    printf("%lld\n", Ans);
    return 0;
}
posted @ 2020-11-14 12:03  When_C  阅读(70)  评论(0编辑  收藏  举报