反思:想到分层,但没有发现其DP的本质;单层预处理能又没用dfs实现导致错误;输出路径更是完全没头绪。。
//代码一
//DP时从上到下(第n层到第一层)
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<iostream>
#define N 260
using namespace std;
int a[17][4][4],b[17][4][4],n;
int dx[4]={-1,1,0,0};
int dy[4]={0,0,-1,1};
bool p[4][4];
int vis[17][4][4];
int pre[17][4][4];
int len[17][N][4][4];
int pre2[17][N][4][4];
int f[17][N][4][4];
char fan[4]={'N','S','W','E'};
string anss;
int food,path,nn,d,x,y;
void dfs(int step,int x,int y,int d)
{
food+=a[nn][x][y];
path<<=2; path+=d; p[x][y]=1;
if (food>vis[step][x][y])
{
vis[step][x][y]=food;
pre[step][x][y]=path;
}
for (int k=0;k<4;k++)
{ int nx=x+dx[k],ny=y+dy[k];
if (nx<0||nx>=4) continue;
if (ny<0||ny>=4) continue;
if (p[nx][ny]) continue;
dfs(step+1,nx,ny,k);
}
food-=a[nn][x][y];
path>>=2; p[x][y]=0;
}
void dp(int i,int j)
{
for (int x=0;x<4;x++)
for (int y=0;y<4;y++)
for (int d=1;d<=16;d++)
for (int st=n+1-nn;st<=((n+1-nn)<<4);st++)
if (st>=d)
if ( (f[nn+1][st-d][i][j]||nn==n)
&&(vis[d][x][y])
&&(f[nn+1][st-d][i][j]+vis[d][x][y]>f[nn][st][x][y])
)
{ f[nn][st][x][y]=f[nn+1][st-d][i][j]+vis[d][x][y];
len[nn][st][x][y]=d-1;
pre2[nn][st][x][y]=pre[d][x][y];
}
}
string esolve(int len,int pp)
{
string re;
re="";
for (int i=1;i<=len;i++)
{ re=fan[pp&3]+re;
pp>>=2;
}
return re;
}
void solve(int k)
{ string re=esolve(len[k][d][x][y],pre2[k][d][x][y]);
anss=re+anss;
if (k==n){ return;}
int len=re.length();
for (int i=0;i<len;i++)
{if (re[i]=='W') y++;
if (re[i]=='E') y--;
if (re[i]=='N') x++;
if (re[i]=='S') x--;
}
anss='D'+anss;
d-=(len+1);
}
void doit()
{ for (int i=n;i>=1;i--)
{ for (int j=0;j<4;j++)
for (int k=0;k<4;k++)
scanf("%d",&a[i][j][k]);
for (int j=0;j<4;j++)
for (int k=0;k<4;k++)
scanf("%d",&b[i][j][k]);
}
memset(f,0,sizeof(f));
scanf("%d%d",&x,&y);
x--;y--;
b[n+1][x][y]=1;
for (nn=n;nn>=1;nn--)
for (int i=0;i<4;i++)
for (int j=0;j<4;j++)
if (b[nn+1][i][j])
{ memset(vis,0,sizeof(vis));
memset(p,0,sizeof(p));
food=0; path=0;
dfs(1,i,j,0);
dp(i,j);
}
double ans=0;
d=0;
for (int i=0;i<4;i++)
for (int j=0;j<4;j++)
for (int k=n;k<=(n<<4);k++)
if (double(f[1][k][i][j])/k>ans)
{
ans=double(f[1][k][i][j])/k;
d=k;
x=i;
y=j;
}
printf("%.4lf\n%d\n",ans,d-1);
anss="";
for (int i=1;i<=n;i++)
solve(i);
cout<<anss<<endl;
}
int main()
{
while (scanf("%d",&n)!=EOF) doit();
}
//代码二
//DP时从下到上(第一层到第n层)
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<iostream>
#define N 260
using namespace std;
int a[17][4][4],b[17][4][4],n;
int dx[4]={-1,1,0,0};
int dy[4]={0,0,-1,1};
bool p[4][4];
int vis[17][4][4];
int pre[17][4][4];
int len[17][N][4][4];
int pre2[17][N][4][4];
int f[17][N][4][4];
char fan[4]={'S','N','E','W'};
int food,path,nn,d,x,y;
void dfs(int step,int x,int y,int d)
{ food+=a[nn][x][y];
path<<=2; path+=d; p[x][y]=1;
if (food>vis[step][x][y])
{ vis[step][x][y]=food;
pre[step][x][y]=path;
}
for (int k=0;k<4;k++)
{ int nx=x+dx[k],ny=y+dy[k];
if (nx<0||nx>=4) continue;
if (ny<0||ny>=4) continue;
if (p[nx][ny]) continue;
dfs(step+1,nx,ny,k);
}
food-=a[nn][x][y];
path>>=2; p[x][y]=0;
}
void dp(int i,int j)
{ for (int x=0;x<4;x++)
for (int y=0;y<4;y++)
for (int d=1;d<=16;d++)
for (int st=nn;st<=(nn<<4);st++)
if (st>=d)
if ( (nn==1||f[nn-1][st-d][i][j])
&&(vis[d][x][y])
&&(f[nn-1][st-d][i][j]+vis[d][x][y]>f[nn][st][x][y])
)
{ f[nn][st][x][y]=f[nn-1][st-d][i][j]+vis[d][x][y];
len[nn][st][x][y]=d-1;
pre2[nn][st][x][y]=pre[d][x][y];
}
}
string esolve(int len,int pp)
{
string re;
re="";
for (int i=1;i<=len;i++)
{ re=re+fan[pp&3];
pp>>=2;
}
return re;
}
void solve(int k)
{ string re=esolve(len[k][d][x][y],pre2[k][d][x][y]);
cout<<re;
if (k==1){cout<<endl; return;}
int len=re.length();
for (int i=0;i<len;i++)
{if (re[i]=='W') y--;
if (re[i]=='E') y++;
if (re[i]=='N') x--;
if (re[i]=='S') x++;
}
cout<<'D';
d-=(len+1);
}
void doit()
{ for (int i=n;i>=1;i--)
{ for (int j=0;j<4;j++)
for (int k=0;k<4;k++)
scanf("%d",&a[i][j][k]);
for (int j=0;j<4;j++)
for (int k=0;k<4;k++)
scanf("%d",&b[i][j][k]);
}
for (int j=0;j<4;j++)
for (int k=0;k<4;k++)
b[1][j][k]=1;
memset(f,0,sizeof(f));
for (nn=1;nn<=n;nn++)
for (int i=0;i<4;i++)
for (int j=0;j<4;j++)
if (b[nn][i][j])
{ memset(vis,0,sizeof(vis));
memset(p,0,sizeof(p));
food=0; path=0;
dfs(1,i,j,0);
dp(i,j);
}
scanf("%d%d",&x,&y);
x--;y--;
double ans=0;
d=0;
for (int k=n;k<=(n<<4);k++)
if (double(f[n][k][x][y])/k>ans)
{
ans=double(f[n][k][x][y])/k;
d=k;
}
printf("%.4lf\n%d\n",ans,d-1);
for (int i=n;i>=1;i--)
solve(i);
}
int main()
{
while (scanf("%d",&n)!=EOF) doit();
}
无论哪种方向,最后输出路径方向一定与dp方向相反