Luogu P1363 幻象迷宫
题目:幻象迷宫
题目链接:https://www.luogu.com.cn/problem/P1363
题意:有一可由无数个\(N\times M\)的迷宫通过拼接无限拓展的图,即图中点\((x,y)\)与点\((x\bmod n,y\bmod m)\)处的迷宫构造完全相同。图中.为路,#为墙,S为起始点。现由起点出发,试问通过上下左右移动是否可到达距离起点的无限远处。
分析:在起始迷宫(即所有点的坐标满足\(0\leq x<n\)且\(0\leq y<m\)的迷宫)内,所有从S点出发可到达的点集记为\(A\)。若从起始迷宫出发,可到达非起始迷宫中的点\((x,y)\)且\((x\bmod n,y\bmod m)\in A\),即表明该点所在迷宫的S点与起始迷宫的S点连通,换而言之,即是说明从起始迷宫的S点出发可以去到无限远处的迷宫的S点。
思路:从起点出发开始搜索,若迷宫中某一相对位置在不同迷宫中走过2次,即说明可从起点走到无限远处。
实现:dfs(更优,有可能更快搜到符合能走到无限远处的条件) / bfs
时间复杂度:迷宫范围为\(N\times M(1≤N,M≤1500)\),样例数\(t\)不超过10,每次搜索不会重复搜索迷宫中同样的点,故时间复杂度为\(O(N\times M\times 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;
}

浙公网安备 33010602011771号