洛谷P1363幻象迷宫
思路:
刚开始,我的思路是能够再次找到S点,就能无限走下去。
然而看反例:
5 5
#####
#...#
#.#S#
#...#
#####
很显然,这不能走出去。
5 5
#####
..#..
#S#.#
..#..
#####
与第一个样例相似。
那么又想到走到的不是本来的S,而是其他图的S。然后就想是不是两层就可以了,他本身是在第一层,然后到边上后就到了第二层。
然而又是全部WA。QAQ。
看反例:
5 5
#..##
#S###
..##.
##...
##.##
他显然可以不断向左向下走无穷远,但我们可以发现,他不能在“下一层”到达S点,他是在“第三层”的时候才到了S点。然后试了试三层……
所以我们拓宽一下思路,我们要找到不是可以到下一个S点。而是,只要我们能第二次经过相对位置相同的一个点,那么我们就可以无限次的经过这个相对点以走到无穷远处。
那么怎么判断走到这一点是之前经过的点还是相对位置上的点呢?
看了大佬的题解,才明白,我们这里用vis数组存的不只是有没有经过(x%n,y%m)点,而是存了hash(x,y),来判断他到的是原本就走过的点还是相对位置相同的点。相对位置相同但是hash值不同即可说明第二次经过某个相对位置相同的点,就表示可以无限走下去。
代码:
#include<bits/stdc++.h>
#define pii pair<int,int>
#define ll long long
#define cl(x) memset(x,0,sizeof(x))
#define ct cerr<<"Time elapsed:"<<1.0*clock()/CLOCKS_PER_SEC<<"s.\n";
const int N=1e6+10;
const int mod=1e3+7;
const int maxn=0x3f3f3f3f;
const int minn=0xc0c0c0c0;
const int inf=99999999;
using namespace std;
char maze[1600][1600];
int vis[1600][1600],n,m,dis[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
struct edge
{
int x,y;
}be;
int ha(int x,int y)
{
return ((x*131+y*1331)%mod+mod)%mod;
}
int bfs()
{
queue<edge> q;
q.push(be);
vis[be.x][be.y]=ha(be.x,be.y);
edge temp,pre,k;
while(!q.empty())
{
int i;
pre=q.front();
q.pop();
for(i=0;i<4;i++)
{
temp.x=pre.x+dis[i][0];
temp.y=pre.y+dis[i][1];
int h=ha(temp.x,temp.y);
k.x=(temp.x+10*n)%n;
k.y=(temp.y+10*m)%m;
if(maze[k.x][k.y]=='#')
continue;
if(!vis[k.x][k.y])
{
q.push(temp);
vis[k.x][k.y]=h;
}
else if(vis[k.x][k.y]!=h)
return 1;
}
}
return 0;
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
int i,j;
for(i=0;i<n;i++)
scanf("%s",maze[i]);
cl(vis);
for(i=0;i<n;i++)
for(j=0;j<m;j++)
{
if(maze[i][j]=='S')
{
be.x=i;
be.y=j;
break;
}
}
int p=bfs();
if(p) printf("Yes\n");
else printf("No\n");
}
return 0;
}