传送门
题解:
构造好题啊。
首先,这道题并没有要求操作数最少。感觉可能最小化操作数是一道不可做题。。。
考虑其实我们不断让当前空位里该放的牌和结果相同,这样我们显然是找到了一条从初始图里空位到结果图里空位的路径,并且在过去的时候顺便把路径上所有牌摆好了。
存在一个问题,不在这条路径上的位置我们还没有访问过,那么这些位置乱掉的牌我们就还没有摆正。
强行把空格子挪过去,然后这个问题就和原问题相同,处理完之后回溯一下即可。
实际上就是在沿路径挪空格的时候,看一下哪个方向的格子是未访问的,把这个方向的连通块处理完之后把空格子挪回来即可。
当然实际上这样也就导致了要访问相同的地方,有一定的无用操作。
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const
cs int N=2e3+7;
int n,m;
char s[N][N],t[N][N];
cs int dx[]={1,0,-1,0};
cs int dy[]={0,1,0,-1};
cs char *str="n<u>",*op="DRUL";
int sx,sy,tx,ty;
bool vis[N][N],use[N][N];
inline int dir(char c){
switch(c){
case 'n':return 0;
case '<':return 1;
case 'u':return 2;
case '>':return 3;
}
}
inline void go(int od){
putchar(op[od]);
int ox=sx+dx[od],oy=sy+dy[od],di=dir(s[ox][oy]);
int nx=ox+dx[di],ny=oy+dy[di];
s[nx][ny]='o',s[sx][sy]=str[od],s[ox][oy]=str[od^2];
sx=nx,sy=ny;
}
void dfs2(int x,int y){
if(vis[x][y]||(x==tx&&y==ty))return ;
int d=dir(t[x][y]);
vis[x][y]=true;x+=dx[d],y+=dy[d];d=dir(s[x][y]);
vis[x][y]=true;x+=dx[d],y+=dy[d];dfs2(x,y);
}
void dfs(int x,int y){
if(use[x][y])return ;use[x][y]=true;dfs2(x,y);
for(int re i=0;i<4;++i){
int nx=x+dx[i],ny=y+dy[i];
if(nx<1||nx>n||ny<1||ny>m||vis[nx][ny])continue;
go(i);dfs(sx,sy);
}
if(x==tx&&y==ty)return ;
go(dir(t[x][y]));dfs(sx,sy);
}
signed main(){
#ifdef zxyoi
freopen("block.in","r",stdin);
#endif
scanf("%d%d",&n,&m);
for(int re i=1;i<=n;++i)scanf("%s",s[i]+1);
for(int re i=1;i<=n;++i)scanf("%s",t[i]+1);
for(int re i=1;i<=n;++i)
for(int re j=1;j<=m;++j){
if(s[i][j]=='o')sx=i,sy=j;
if(t[i][j]=='o')tx=i,ty=j;
}dfs(sx,sy);
return 0;
}