题目链接:http://codeforces.com/problemset/problem/580/D
题目大意:
有n盘菜每个菜都有一个满意度,k个规则,每个规则由x y c组成,表示如果再y之前吃x那么满意度会额外增加c,
现在凯迪想吃m盘菜,并且满意度最大,请求出满意度。
解题思路:
状压DP,设dp[i][j]表示在状态i并且最后一道菜放在位置j时的最大满意度。
注意要处理好一道菜时的情况,以及注意二进制表示中1的个数超过m的情况。
代码:
1 #include<bits/stdc++.h> 2 #define lc(a) (a<<1) 3 #define rc(a) (a<<1|1) 4 #define MID(a,b) ((a+b)>>1) 5 #define fin(name) freopen(name,"r",stdin) 6 #define fout(name) freopen(name,"w",stdout) 7 #define clr(arr,val) memset(arr,val,sizeof(arr)) 8 #define _for(i,start,end) for(int i=start;i<=end;i++) 9 #define FAST_IO ios::sync_with_stdio(false);cin.tie(0); 10 using namespace std; 11 typedef long long LL; 12 const int N=25; 13 const int INF=0x3f3f3f3f; 14 const double eps=1e-10; 15 16 LL ans,n,m,p; 17 LL val[N],mp[N][N],dp[1<<18][N];//dp[i][j]表示i的状态下最后一个盘子选择第j个的最优解 18 19 int main(){ 20 FAST_IO; 21 cin>>n>>m>>p; 22 for(int i=0;i<n;i++){ 23 cin>>val[i]; 24 } 25 for(int i=1;i<=p;i++){ 26 int x,y,c; 27 cin>>x>>y>>c; 28 mp[x-1][y-1]=c; 29 } 30 memset(dp,-1,sizeof(dp)); 31 ans=0; 32 int lim=(1<<n); 33 for(int i=1;i<lim;i++){ 34 int cnt=0; 35 for(int j=0;j<n;j++){ 36 int tmp=(1<<j); 37 if(tmp&i) 38 cnt++; 39 } 40 //点菜数不能>m 41 if(cnt>m) continue; 42 for(int j=0;j<n;j++){ 43 int tmp=(1<<j); 44 if(tmp&i){ 45 int pre=i-tmp; 46 //单个菜的时候没有前一个菜所以直接赋值,否则会被0 x类型的rule影响 47 if(cnt==1) 48 dp[i][j]=val[j]; 49 else{ 50 for(int k=0;k<n;k++){ 51 if(dp[pre][k]==-1) continue; 52 dp[i][j]=max(dp[i][j],dp[pre][k]+mp[k][j]+val[j]); 53 } 54 } 55 ans=max(dp[i][j],ans); 56 } 57 } 58 } 59 cout<<ans<<endl; 60 return 0; 61 }