dp,阶段就是步数。
本蒟蒻想不出来,只好用题解大法:四个方向的走路,dp的阶段是步数,每个点可以由四个方向转移而来。这是逆序做的。他这样做的好吃是最后回到原点,然后逆序找字典序最小即可。
独立思考下,如果从原点出发,那么向四个方向走,需要找出最大值和字典序最小的路径。因此,对每个点,值变化的时候更新值,值不变但路径更小的时候也更新。
#include<cstdio>
#include<string>
#include<iostream>
using namespace std;
const int N=1000,T=31;
const int dx[]={1,0,0,-1},dy[]={0,1,-1,0};
string d="ENSW";
//方向增量按字母字典序的顺序给出:E,N,S,W
int n,m,k,i,j,s,t,x[N],y[N],p[N],q[N],g[T*2][T*2],f[T][T*2][T*2],u,v,ans=0;
int ew[70],ns[70],Tk;
string st[T][T*2][T*2];
string minst="Z";
//因为下标不能为负,所以向南向西的负数要加上T使之为正
int max(int x,int y){return x>y?x:y;}
int abs(int x){return x>0?x:-x;}
int main(){
for(int i=1;i<T;i++)
for(int j=0;j<2*T;j++)
for(int k=0;k<2*T;k++)st[i][j][k]+='Z';
scanf("%d%d%d",&n,&m,&k);
Tk= k+1;
for(i=0;i<n;i++)
scanf("%d%d",x+i,y+i);
for(i=0;i<m;i++)
scanf("%d%d",p+i,q+i);
for(i=0;i<n;i++)
for(j=0;j<m;j++)
if(abs(p[j]-x[i])+abs(q[j]-y[i])<=k)
g[p[j]-x[i]+Tk][q[j]-y[i]+Tk]++;
for(t=0;t<k;t++)
for(u=Tk-t;u<=Tk+t;u++)
for(v=Tk-t;v<=Tk+t;v++){
if(abs(u-Tk)+abs(v-Tk)>t)continue;
for(int i=0;i<4;i++){
if(f[t+1][u+dx[i]][v+dy[i]]<f[t][u][v]+g[u+dx[i]][v+dy[i]]){
f[t+1][u+dx[i]][v+dy[i]]=f[t][u][v]+g[u+dx[i]][v+dy[i]];
st[t+1][u+dx[i]][v+dy[i]]=st[t][u][v]+d[i];
}
else if(f[t+1][u+dx[i]][v+dy[i]]==f[t][u][v]+g[u+dx[i]][v+dy[i]]&&
st[t+1][u+dx[i]][v+dy[i]]>st[t][u][v]+d[i])
st[t+1][u+dx[i]][v+dy[i]]=st[t][u][v]+d[i];
ans=max(ans,f[t+1][u+dx[i]][v+dy[i]]);
}
}
for(u=Tk-t;u<=Tk+t;u++)
for(v=Tk-t;v<=Tk+t;v++)
if(f[k][u][v]==ans)minst=min(minst,st[k][u][v]);
cout<<ans<<endl<<minst<<endl;
return 0;
}