从起点走到终点,每走一步消耗一点能量,吃到水果增加相应的能量,-1表示该格子不能走,同一个格子可以重复走多次,问达到终点时最多能获得多少能量。
水果数量不超过17,所以我们可以用状态压缩dp,首先bfs预处理出各个水果以及起点终点的距离,然后进行dp。
dp二维表示某一种状态,以及当前状态下最后一个到的点。要考虑走到某一点时,它的能量是否足够支持它走到下个点。
代码如下:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<iostream>
#include<queue>
#define INF 2000000000
#define maxm (1<<19)
int map[258][258],dis[258][258],fdis[20][20],dp[maxm][19],have[20][3],idx,m,n,queue[100005][2],b[4][2]={0,1,1,0,-1,0,0,-1};
int max(int a,int b)
{
return a>b?a:b;
}
int change(int xx,int yy)
{
for(int i=0;i<=idx;i++)
{
if(have[i][0]==xx&&have[i][1]==yy)
return i;
}
}
void bfs(int s)
{
int begin,end,x,y,xx,yy,t,i,j,k;
memset(dis,-1,sizeof(dis));
x=have[s][0];y=have[s][1];
dis[x][y]=0;
begin=0;end=1;
queue[0][0]=x;
queue[0][1]=y;
while(begin!=end)
{
x=queue[begin][0];
y=queue[begin][1];
begin++;
for(i=0;i<4;i++)
{
xx=x+b[i][0];yy=y+b[i][1];
if(xx>0&&xx<=m&&yy>0&&yy<=n&&map[xx][yy]!=-1&&dis[xx][yy]==-1)
{
dis[xx][yy]=dis[x][y]+1;
if(map[xx][yy]>0||(xx==1&&yy==1)||(xx==m&&yy==n))
{
t=change(xx,yy);
fdis[s][t]=fdis[t][s]=dis[xx][yy];
}
queue[end][0]=xx;
queue[end][1]=yy;
end++;
}
}
}
}
int main()
{
int i,j,k,l,re;
while(scanf("%d%d",&m,&n)!=EOF)
{
memset(fdis,-1,sizeof(fdis));
for(i=1;i<=m;i++)
{
for(j=1;j<=n;j++)
{
scanf("%d",&map[i][j]);
}
}
have[0][0]=1;
have[0][1]=1;
have[0][2]=map[1][1];
idx=0;
for(i=1;i<=m;i++)
for(j=1;j<=n;j++)
{
if(i==1&&j==1)
continue;
if(map[i][j]>0)
{
have[++idx][0]=i;
have[idx][1]=j;
have[idx][2]=map[i][j];
}
}
if(map[m][n]==0)
{
have[++idx][0]=m;
have[idx][1]=n;
have[idx][2]=0;
}
for(i=0;i<=idx;i++)
{
bfs(i);
}
memset(dp,-1,sizeof(dp));
re=-1;
dp[0][0]=map[1][1];
if(m==1&&n==1)
{
printf("%d\n",map[m][n]);
continue;
}
if(map[1][1]==0)
{
printf("you loss!\n");
continue;
}
for(i=0;i<=idx;i++)
fdis[i][i]=0;
for(i=1;i<(1<<idx);i++)
{
for(j=1;j<=idx;j++)
{
if(((1<<(j-1))&i)==(1<<(j-1)))
{
for(k=0;k<=idx;k++)
{
if(k!=j&&dp[i-(1<<(j-1))][k]!=-1&&fdis[k][j]!=-1&&(dp[i-(1<<(j-1))][k]-fdis[k][j]>=0))
dp[i][j]=max(dp[i-(1<<(j-1))][k]-fdis[k][j]+have[j][2],dp[i][j]);
}
}
if(j==idx&&dp[i][j]>re)
re=dp[i][j];
if(j!=idx&&fdis[j][idx]!=-1&&dp[i][j]>=fdis[j][idx]&&dp[i][j]-fdis[j][idx]>re)
re=dp[i][j]-fdis[j][idx];
}
}
if(re==-1)
printf("you loss!\n");
else
printf("%d\n",re);
}
return 0;
}