Luogu P1363 幻象迷宫

题目:幻象迷宫

题目链接:https://www.luogu.com.cn/problem/P1363

题意:有一可由无数个N×M的迷宫通过拼接无限拓展的图,即图中点(x,y)与点(xmodn,ymodm)处的迷宫构造完全相同。图中.为路,#为墙,S为起始点。现由起点出发,试问通过上下左右移动是否可到达距离起点的无限远处。

分析:在起始迷宫(即所有点的坐标满足0x<n0y<m的迷宫)内,所有从S点出发可到达的点集记为A。若从起始迷宫出发,可到达非起始迷宫中的点(x,y)(xmodn,ymodm)A,即表明该点所在迷宫的S点与起始迷宫的S点连通,换而言之,即是说明从起始迷宫的S点出发可以去到无限远处的迷宫的S点。

思路:从起点出发开始搜索,若迷宫中某一相对位置在不同迷宫中走过2次,即说明可从起点走到无限远处。

实现:dfs(更优,有可能更快搜到符合能走到无限远处的条件) / bfs

时间复杂度:迷宫范围为N×M(1N,M1500),样例数t不超过10,每次搜索不会重复搜索迷宫中同样的点,故时间复杂度为O(N×M×t)

dfs解法参考代码:

【注意】该题本质是能否到达问题,不需回溯;求路径数问题才要回溯。

#include<bits/stdc++.h>
#define int long long
using namespace std;
#define endl '\n'

int n,m,flag,ax,ay;
char g[1510][1510];
int st[1510][1510];
int to[1510][1510][2];//记录点(x,y)被搜索到的迷宫所在图中的位置 
int dx[4]={-1,1,0,0},dy[4]={0,0,1,-1};

void dfs(int x,int y,int sx,int sy){
	//(x,y)表示 点在迷宫中的一相对位置(即点的位置)
	//(sx,sy)表示 当前点所在的迷宫处于图中的位置(即迷宫的位置)
	if(flag) return;
	for(int i=0;i<4;i++){
		int nx=x+dx[i],ny=y+dy[i];
		int nsx=sx,nsy=sy;
		if(nx>=n) nsy++;
		else if(nx<0) nsy--;
		else if(ny>=m) nsx++;
		else if(ny<0) nsx--;
		nx=(nx+n)%n,ny=(ny+m)%m;
		if(g[nx][ny]=='#') continue;
		if(st[nx][ny]){
			if(nsx!=to[nx][ny][0]||nsy!=to[nx][ny][1]){
				flag=1;//若在不同迷宫到达过相同位置->Yes
				return;
			} 
			else continue;
		}
		st[nx][ny]=1;
		to[nx][ny][0]=nsx;
		to[nx][ny][1]=nsy;
		dfs(nx,ny,nsx,nsy);
	}
}

void solve(){
	while(cin>>n>>m){
		flag=0;
		memset(st,0,sizeof(st));
		for(int i=0;i<n;i++){
			for(int j=0;j<m;j++){
				cin>>g[i][j];
				if(g[i][j]=='S') ax=i,ay=j;
			}
		}
		st[ax][ay]=1;
		to[ax][ay][0]=0;
		to[ax][ay][1]=0;
		dfs(ax,ay,0,0);
		if(flag) cout<<"Yes\n";
		else cout<<"No\n";
	}
}

signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	int T=1; 
	//cin>>T;
	while(T--) solve();
	return 0;
}


bfs解法参考代码:

#include<bits/stdc++.h>
#define int long long
using namespace std;
#define endl '\n'

int n,m,flag,ax,ay;
char g[1510][1510];
int st[1510][1510];
int to[1510][1510][2];//记录点(x,y)被搜索到的迷宫所在图中的位置 
int dx[4]={-1,1,0,0},dy[4]={0,0,1,-1};

struct place{
	int x,y,sx,sy;
	//(x,y)表示 点在迷宫中的一相对位置(即点的位置)
	//(sx,sy)表示 当前点所在的迷宫处于图中的位置(即迷宫的位置) 
};

void solve(){
	while(cin>>n>>m){
		flag=0;
		memset(st,0,sizeof(st));
		for(int i=0;i<n;i++){
			for(int j=0;j<m;j++){
				cin>>g[i][j];
				if(g[i][j]=='S') ax=i,ay=j;
			}
		}
		queue<place>q;
		st[ax][ay]=1;
		to[ax][ay][0]=0;
		to[ax][ay][1]=0;
		q.push({ax,ay,0,0});
		//先标记,再入队,可减少入队数 
		while(!q.empty()){
			place now=q.front();
			q.pop();
			for(int i=0;i<4;i++){
				int nx=now.x+dx[i],ny=now.y+dy[i];
				int nsx=now.sx,nsy=now.sy;
				if(nx<0) nsy--;
				else if(nx>=n) nsy++;
				else if(ny<0) nsx--;
				else if(ny>=m) nsx++;
				nx=(nx+n)%n,ny=(ny+m)%m;
				if(g[nx][ny]=='#') continue;
				if(st[nx][ny]){
					if(to[nx][ny][0]!=nsx||to[nx][ny][1]!=nsy){
						//若在不同迷宫到达过相同位置->Yes 
						flag=1;
						break;
					}
				} 
				else{
					st[nx][ny]=1; 
					to[nx][ny][0]=nsx;
					to[nx][ny][1]=nsy;
					q.push({nx,ny,nsx,nsy});
				}
			}
		} 
		if(flag) cout<<"Yes\n";
		else cout<<"No\n";
	}
}

signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	int T=1; 
	//cin>>T;
	while(T--) solve();
	return 0;
}


posted @   jojo_ojoj  阅读(11)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
/*
点击右上角即可分享
微信分享提示