数据有点多有点乱的一道题,需要一些预处理,但是把思路层层理顺后DP思路就很显然了,用n位2进制数表示剩下的人的状态,第i位为1时表示有这人,为0时表示没有这个人。则状态有m*(2^n)个,状态转移比较容易。
这题可能测试数据很多,第一次超时了,1400ms左右,优化了输入降至1100ms,然后发现一个早该发现的优化,就是如果j状态能到达i状态,那么j>i是一定的。改过交,3A。这个应该可以早发现的,没有1A就是失败。
#include <cstdio> #include <cstring> int n,m; int cost[12][2048]; int bonus[2048]; int profit[12][2048]; int dp[12][2048]; int v[12][12],p[12],b[12][12]; int posscome[1200][1200]; int pt[1200]; bool cango[1300][1300]; int maxbound; char readintch; void readint(int &x) { while(readintch = getchar(),readintch<'0' || readintch>'9'); x = readintch - '0'; while(readintch = getchar(),readintch>='0' && readintch<='9') x = x*10 + readintch - '0'; } void calc_cost() { int i,j,k,cnt; for(i=1;i<=m;i++) { for(j=0;j<=maxbound;j++) { cnt = 0; k=j; while(k!=0) { if(k&1) { cnt++; } k = k>>1; } cost[i][j] = cnt*p[i]; } } } void calc_bonus() { int i,j,k; bool state[12]; for(i=0;i<=maxbound;i++) { k = i; for(j=n;j>=1;j--) { state[j] = k&1; k = k>>1; } bonus[i] = 0; for(j=1;j<=n;j++) { for(k=j+1;k<=n;k++) { if(state[k] && state[j]) { bonus[i] += b[j][k]; } } } } } void calc_profit() { int i,j,k,p; bool state; for(i=1;i<=m;i++) { for(j=0;j<=maxbound;j++) { profit[i][j] = 0; k=j; for(p=n;p>=1;p--) { state = k&1; if(state) { profit[i][j] += v[p][i]; } k = k>>1; } } } } int ans = 0; int max(int a,int b) { return (a>b?a:b); } bool test(int pos,int from,int to) { if(pos == 1) return true; int k; for(k=n;k>=1;k--) { if( ( (from&1)==0) && ((to&1)==1)) return false; from = from>>1; to = to>>1; } return true; } void calc_cango() { int i,j,k,from,to; memset(pt,0,sizeof(pt)); for(i=0;i<=1023;i++) { for(j=0;j<=1023;j++) { from = i,to = j; for(k=10;k>=1;k--) { if( ( (from&1)==0) && ((to&1)==1)) { cango[i][j] = false; break; } from = from>>1; to = to>>1; } if(k==0) { cango[i][j] = true; posscome[j][pt[j]++] = i; } } } for(i=0;i<=10;i++) { printf("i: %d ",i); for(j=0;j<10;j++) { printf("%d ",posscome[i][j]); } printf("\n"); } /* for(i=1;i<=5;i++) { for(j=1;j<=5;j++) { printf("%d ",cango[i][j]); } printf("\n"); } */ } void makedp() { int i,j,k,tmp,tmpk; for(i=0;i<=m;i++) { for(j=0;j<=maxbound;j++) dp[i][j] = -1000000000; } dp[0][0] = 0; for(i=1;i<=m;i++) { for(j=0;j<=maxbound;j++) { if(i==1) dp[i][j] = profit[i][j] + bonus[j] - cost[i][j]; else { for(tmpk = 0;tmpk<pt[i] && posscome[i][tmpk] <=maxbound;tmpk++) //for(k=0;k<=maxbound;k++) { //if(cango[k][j]) k = posscome[i][tmpk]; tmp = dp[i-1][k] + profit[i][j] + bonus[j] - cost[i][j]; if(tmp > dp[i][j]) dp[i][j] = tmp; } } if(dp[i][j] > ans) { ans = dp[i][j]; //printf("ans: %d i:%d j:%d\n",ans,i,j); } } } } int main() { int i,j,k; calc_cango(); while(readint(n),readint(m),n||m) { ans = -1; maxbound = (1<<n)-1; for(i=1;i<=m;i++) readint(p[i]); //scanf("%d",&p[i]); for(i=1;i<=n;i++) { for(j=1;j<=m;j++) { readint(v[i][j]); //scanf("%d",&v[i][j]); } } for(i=1;i<=n;i++) { for(j=1;j<=n;j++) { readint(b[i][j]); //scanf("%d",&b[i][j]); } } calc_cost(); calc_bonus(); calc_profit(); makedp(); if(ans <= 0) { printf("STAY HOME\n"); } else { printf("%d\n",ans); } for(i=1;i<=m;i++) { for(j=0;j<=maxbound;j++) { printf("%d %d %d\n",i,j,dp[i][j]); } } } return 0; }