codeforces 580D
题意:
饭
店
里
有
n
种
菜
,
吃
第
i
种
菜
带
来
a
i
点
满
意
度
,
你
需
要
吃
m
种
菜
才
能
吃
饱
,
吃
的
菜
品
不
能
重
复
。
饭店里有n种菜,吃第i种菜带来a_i点满意度,你需要吃m种菜才能吃饱,吃的菜品不能重复。
饭店里有n种菜,吃第i种菜带来ai点满意度,你需要吃m种菜才能吃饱,吃的菜品不能重复。
给
出
k
组
x
i
、
y
i
、
c
i
,
表
示
先
吃
第
x
i
种
菜
,
再
吃
第
y
i
种
菜
,
可
以
额
外
带
来
c
i
点
满
意
度
。
给出k组x_i、y_i、c_i,表示先吃第x_i种菜,再吃第y_i种菜,可以额外带来c_i点满意度。
给出k组xi、yi、ci,表示先吃第xi种菜,再吃第yi种菜,可以额外带来ci点满意度。
问
吃
饱
后
的
最
大
满
意
度
。
问吃饱后的最大满意度。
问吃饱后的最大满意度。
题解:
d p [ i ] [ j ] 表 示 i 状 态 下 最 后 一 盘 菜 为 j 的 满 意 度 , 其 中 二 进 制 状 态 下 的 i 的 各 位 1 和 0 代 表 吃 与 不 吃 。 dp[i][j]表示i状态下最后一盘菜为j的满意度,其中二进制状态下的i的各位1和0代表吃与不吃。 dp[i][j]表示i状态下最后一盘菜为j的满意度,其中二进制状态下的i的各位1和0代表吃与不吃。
- 若 二 进 制 状 态 下 的 i 的 第 j 位 等 于 1 , 而 第 k 位 等 于 0 , d p [ i ∣ ( 1 < < k − 1 ) ] [ k ] = m a x ( d p [ i ∣ ( 1 < < k − 1 ) ] [ k ] , d p [ i ] [ j ] + a [ k ] + v [ j ] [ k ] ) 若二进制状态下的i的第j位等于1,而第k位等于0,dp[i | (1<<k-1)][k] = max(dp[i | (1<<k-1)][k], dp[i][j]+a[k]+v[j][k]) 若二进制状态下的i的第j位等于1,而第k位等于0,dp[i∣(1<<k−1)][k]=max(dp[i∣(1<<k−1)][k],dp[i][j]+a[k]+v[j][k])
- 遍 历 1 < < n 种 状 态 , 若 二 进 制 状 态 下 的 i 的 各 位 之 和 等 于 m , 则 状 态 合 法 遍历1<<n种状态,若二进制状态下的i的各位之和等于m,则状态合法 遍历1<<n种状态,若二进制状态下的i的各位之和等于m,则状态合法
#include <bits\stdc++.h>
using namespace std;
typedef long long ll;
ll a[20], v[20][20];
ll dp[1<<18][20];
int main() {
int n, m, k, x, y;
cin >> n >> m >> k;
for(int i = 1 ; i <= n ; i++){
cin >> a[i];
dp[1<<(i-1)][i] = a[i];
}
ll c;
for(int i = 1 ; i <= k ; i++){
cin >> x >> y >> c;
v[x][y] = c;
}
ll ans = 0;
for(int i = 1 ; i < (1<<n) ; i++){
for(int j = 1 ; j <= n ; j++){
if(i & 1<<(j-1)){
for(int k = 1 ; k <= n ; k++){
if(!(i & 1<<(k-1))){
dp[i | (1<<k-1)][k] = max(dp[i | (1<<k-1)][k], dp[i][j]+a[k]+v[j][k]);
}
}
}
}
}
for(int i = 1 ; i < (1<<n) ; i++){
if(__builtin_popcount(i) == m){
for(int k = 1 ; k <= n ; k++){
ans = max(ans, dp[i][k]);
}
}
}
cout << ans << endl;
return 0;
}