题意:
餐厅共有 n n n 道菜,举办宴会要选 m m m 道不重复的菜,并满足以下条件:
- 首先,第 i i i 道菜的美味值为 a i a_i ai,而一个宴会的基础美味值等于菜单上所有菜品的美味值之和。
- 其次,上菜的流程会影响最终的美味值,一共有 k k k 条规则。第 i i i 条规则对应两道菜 x i x_i xi 和 y i y_i yi,如果在上菜流程中, y i y_i yi 紧跟在 x i x_i xi 后面,则宴会的美味值会提升 c i c_i ci 点。
求宴会的最大美味值。
思路:
状压DP。
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]表示状态为
i
i
i ,最后上的一道菜是第
j
j
j 道菜时的最大值。那么转移方程就显而易见了。
(队友说的,我也就这么认为了。我代码写得巨丑)
#include<bits/stdc++.h>
#define ll long long
#define ms(x,a) memset(x,a,sizeof(x))
using namespace std;
const int maxn = 1 << 18 | 1;
int a[20],G[20][20];
ll dp[maxn][20];
int main(){
int n,m,k;
scanf("%d%d%d",&n,&m,&k);
for(int i = 1;i <= n; ++i){
scanf("%d",&a[i]);
}
for(int i = 1;i <= k; ++i){
int x,y,c;
scanf("%d%d%d",&x,&y,&c);
G[x][y] = c;
}
ms(dp,0);
ll ans = 0;
for(int i = 0;i < (1 << n); ++i){
for(int k = 1;k <= n; ++k){
if((i & (1 << (k - 1))) == 0){
int f = 1;
for(int j = 1;j <= n; ++j){
if((i | (1 << (j - 1))) == i){
++f;
dp[i | (1 << (k - 1))][k] = max(dp[i | (1 << (k - 1))][k],dp[i][j] + G[j][k] + a[k]);
}
}
dp[i | (1 << (k - 1))][k] = max(dp[i | (1 << (k - 1))][k],1LL * a[k]);
if(f == m)ans = max(ans,dp[i | (1 << (k - 1))][k]);
}
}
}
cout<<ans<<endl;
return 0;
}