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;
}