【动态规划专练-状压DP】CodeForces 580D (1800)
D. Kefa and Dishes
范围比较小可以用二进制暴力枚举
限制条件:前后相邻的拿的物品有贡献,所以状态要记录最后一个拿的物品,记录所有物品的状态,暴力枚举物品状态,枚举前一个后一个物品
点击查看代码
#include <iostream>
#include <map>
#include <vector>
#include <algorithm>
#include <stack>
#include <cstdio>
#include <queue>
#include <set>
#include<sstream>
#include <cstring>
#include <cmath>
#include <bitset>
//#pragma GCC optimize(2);
#define IOS ios::sync_with_stdio(false);
#define mm(a, b) memset(a, b, sizeof(a))
const double PI = acos(-1.0);
typedef long long ll;
const int N = 1e5+5;
const int M = N*2;
const double eps =1e-8;
const ll mod = 998244353;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const double maxd = -1e9;
const int maxn = 500;
using namespace std;
typedef pair<string,int> PII;
int a[20];
int g[20][20];
ll f[20][1<<20];
//dp[i][j] 最后吃的是i,当前的状态j
// k上一次吃的是k ,上一状态q
//dp[i][j] = max(dp[i][j],dp[k][q]+a[i]+g[k][i]);
int main(){
int n,m,k,xi,yi,ci;
cin>>n>>m>>k;
for(int i=0;i<n;i++)cin>>a[i];
while(k--){
cin>>xi>>yi>>ci;
g[--xi][--yi] = ci;
}
ll ans = 0;
memset(f,0,sizeof f);
for(int j=0;j<(1<<n);j++){
int sum = 1;
int t = j;
while(t&(t-1)) t= t&(t-1),sum++;//统计吃了多少个
for(int i=0;i<n;i++){
if(j&(1<<i)){
for(int k=0;k<n;k++){
if(j&(1<<k)){
int q = j - (1<<i);
f[i][j] = max(f[i][j],f[k][q]+a[i]+g[k][i]);
}
}
}
if(sum == m) ans = max(ans,f[i][j]);
}
}
cout<<ans<<endl;
return 0;
}