思路
(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
", Ans);
return 0;
}