数据有点多有点乱的一道题,需要一些预处理,但是把思路层层理顺后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;
}