【SNOI2019】积木(构造)(回溯法)

传送门


题解:

构造好题啊。

首先,这道题并没有要求操作数最少。感觉可能最小化操作数是一道不可做题。。。

考虑其实我们不断让当前空位里该放的牌和结果相同,这样我们显然是找到了一条从初始图里空位到结果图里空位的路径,并且在过去的时候顺便把路径上所有牌摆好了。

存在一个问题,不在这条路径上的位置我们还没有访问过,那么这些位置乱掉的牌我们就还没有摆正。

强行把空格子挪过去,然后这个问题就和原问题相同,处理完之后回溯一下即可。

实际上就是在沿路径挪空格的时候,看一下哪个方向的格子是未访问的,把这个方向的连通块处理完之后把空格子挪回来即可。

当然实际上这样也就导致了要访问相同的地方,有一定的无用操作。


代码:

#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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值