方法: DP
解析:
第一眼搜索题,复杂度不允许dfs,而且牛的数量太多不能bfs,迭代更不可能,A*不会估价,可能记忆化?
等等记忆化我还搜个毛线…
直接改成DP就好了。
状态很好想很简单,但是这个路径简直….丧心病狂!
f[i][j][k]表示横向走了(i-31),纵向走了(j-31)用了k次的最大值。
所以我们要预处理map[i][j]表示横向走到(i-31),纵向走到(j-31),这么一下对答案的贡献。
然后我就要吐槽了,这个题如果你不处理一些奇怪的点,比如走到坐标为x,0或是0,y的地方是合法的!合法的!
所以题里那个>=1不是限制这个的?简直丧病!
然后就是欢快地搜路径辣。
到着搜所有路径,字典序的方向优先选用。
最后正着跑一边就好了。
说起来挺简单。
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 35
#define INF 0x3f3f3f3f
using namespace std;
int n,m,k;
struct node
{
int x,y;
}pt[1010];
int f[N<<1][N<<1][N];
char pre[N<<1][N<<1][N];
int map[N<<1][N<<1];
int map_ori[1010][1010];
int xx[5]={0,-1,0,0,1};
int yy[5]={0,0,-1,1,0};
bool canbetheend[N][N];
char printout[N];
char comp[N];
char pick[N];
void init_map()
{
for(int i=0;i<=62;i++)
{
for(int j=0;j<=62;j++)
{
int basex,basey;
basex=i-31,basey=j-31;
int flag=0;
for(int l=1;l<=n;l++)
{
if(i==29&&j==30)
{
flag++;
flag--;
}
int x=pt[l].x,y=pt[l].y;
if(x+basex<=0||y+basey<=0||x+basex>1000||y+basey>1000){flag=1;continue;}
map[i][j]+=map_ori[x+basex][y+basey];
}
}
}
}
int main()
{
pick[1]='W',pick[2]='S',pick[3]='N',pick[4]='E';
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++)scanf("%d%d",&pt[i].x,&pt[i].y);
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
map_ori[x][y]++;
}
init_map();
int ans=0;
for(int i=0;i<=k;i++)
{
for(int j=0;j<=62;j++)
{
for(int l=0;l<=62;l++)
{
f[j][l][i]=-INF,pre[j][l][i]='Z';
}
}
}
f[31][31][0]=0;
for(int i=1;i<=k;i++)
{
for(int j=1;j<=61;j++)
{
for(int l=1;l<=61;l++)
{
f[j][l][i]=max(max(f[j-1][l][i-1],f[j][l-1][i-1]),max(f[j][l+1][i-1],f[j+1][l][i-1]))+map[j][l];
if(i==k)
{
if(f[j][l][i]>ans)
{
ans=f[j][l][i];
}
}
}
}
}
for(int i=1;i<=61;i++)
{
for(int j=1;j<=61;j++)
{
if(f[i][j][k]==ans)
{
pre[i][j][k]='A';
}
}
}
for(int l=k-1;l>=0;l--)
{
for(int i=1;i<=61;i++)
{
for(int j=1;j<=61;j++)
{
for(int o=1;o<=4;o++)
{
if(f[i][j][l]+map[i+xx[o]][j+yy[o]]==f[i+xx[o]][j+yy[o]][l+1]&&pre[i+xx[o]][j+yy[o]][l+1]<'Z')
{
pre[i][j][l]=pick[o];
}
}
}
}
}
printf("%d\n",ans);
int li=31,lj=31;
for(int i=0;i<k;i++)
{
printf("%c",pre[li][lj][i]);
switch(pre[li][lj][i])
{
case 'E':li++;break;
case 'N':lj++;break;
case 'S':lj--;break;
case 'W':li--;break;
}
}
cout<<endl;
}