原题链接:http://codeforces.com/problemset/problem/580/D
题意:在n个数字中有顺序地选择m个数字,每个数字对应有个值ai,每取一个数字答案加上ai,并且存在k个关系:x y c,如果x恰好排在y的前面,那么答案再加上ci的值。输出最大值。
思路:状压dp。dp[i][j]中,i是已经选了若干个数的情况,j是最后一个被选取的数,i从选取1个到m个枚举下去,j从第1个数到第n个数进行枚举就能得到答案。
AC代码:
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 using namespace std; 5 typedef long long LL; 6 LL a[20],d[20][20],pos[20]; 7 LL dp[1<<19][20]; 8 int main() 9 { 10 pos[0]=1; 11 for(int i=1;i<=19;i++) pos[i]=pos[i-1]<<1; 12 memset(dp,0, sizeof(dp)); 13 memset(d, 0, sizeof(d)); 14 int n,m,k,x,y,c; 15 scanf("%d %d %d", &n, &m, &k); 16 for(int i=0;i<n;i++) scanf("%I64d", a+i); 17 for(int i=0;i<k;i++){ 18 scanf("%d %d %d",&x, &y, &c); 19 x--,y--; 20 d[x][y]=c; 21 } 22 int num; 23 for(int i=0;i<n;i++) dp[pos[i]][i]=a[i]; 24 25 for(int t=1;t<m;t++){ 26 for(int i=0;i<n;i++){ 27 for(int j=0;j<pos[n];j++){ 28 if(j&pos[i]) continue; 29 30 num=0;//cout<<'*'<<endl; 31 k=j; 32 while(k){ 33 if(k&1) 34 num++; 35 k>>=1; 36 } 37 if(num!=t) continue; 38 39 for(int s=0;s<n;s++) 40 if(s!=i&&(j&pos[s])){ 41 dp[j|pos[i]][i]=max(dp[j|pos[i]][i], dp[j][s]+d[s][i]+a[i]); 42 //cout<<s<<' '<<j<<' '<<i<<' '<<d[s][i]<<' '<<dp[j|pos[i]][i]<<endl; 43 } 44 45 } 46 } 47 } 48 49 LL ans=0; 50 for(int i=0;i<pos[n];i++){ 51 num=0; 52 k=i; 53 while(k){ 54 if(k&1) 55 num++; 56 k>>=1; 57 } 58 if(num!=m) continue; 59 60 for(int j=0;j<n;j++) if(pos[j]&i) ans=max(ans, dp[i][j]); 61 } 62 printf("%I64d ", ans); 63 return 0; 64 }