【洛谷1363】幻象迷宫
难得的搜索好题
原题:
n,m<=1500
感觉这题有点难度
逐步想出思路是不会的,只能是灵稽一动,直接发现正解
bfs+记忆化,每个点记忆的数据为从源点到此处的x和y方向的变化量
从点a到b转移时,如果b没来过就正常转移,如果来过则进行判断
如果a的变化量+从a到b的变化量-b的变化量不为(0,0),则此图有解
如果全图搜索完毕没有发现符合上述条件的点对,则出不去
为什么呢?
“a的变化量+从a到b的变化量-b的变化量”本质是把从源点到b的路径反过来,构成一条从源点到a,再到b,再到另一个源点的过程
如果这条路径的变化量不为零向量,则显然能走到无穷远
这条路径一定经过源点s,那么是否存在能走到无穷远且不能走到s的路径呢?
不存在,因为在任意一个点都可以原地折返回到s再回来
进一步地说,任意两个可到达的点a和b都来自源点,那么在任意一条路径中,拿出两个点,都可以找出一条经过s的衍生路径
所以保证上面的做法不会漏解
这道题的关键在于灵活设置记忆化数据,然后发现位移向量的性质,并利用bfs“所有可到达的点都来自源点”的特点
代码技巧:
因为存在传送门(即从右边出来可以到左边)的设定,因此此题下标最好从0开始,这样即便于id函数压缩状态,又便于快速处理传送操作
代码:
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 int fx[4]={1,-1,0,0},fy[4]={0,0,1,-1}; 5 struct nds{int x,y;}f[1500][1500]; 6 int n,m,a[1500][1500]; char s[1500]; 7 int sx,sy; 8 int q[3100000],hd=0; 9 int gtid(int x,int y){ return x*m+y;} 10 bool bfs(){ 11 q[hd=1]=gtid(sx,sy); 12 for(int k=1;k<=hd;++k){ 13 int x=q[k]/m,y=q[k]%m; 14 for(int i=0;i<4;++i){ 15 int tx=(x+fx[i]+n)%n,ty=(y+fy[i]+m)%m; 16 if(a[tx][ty]){ 17 if(!f[tx][ty].x && !f[tx][ty].y && (tx!=sx || ty!=sy)){ 18 f[tx][ty]=(nds){f[x][y].x+fx[i],f[x][y].y+fy[i]}; 19 q[++hd]=gtid(tx,ty); 20 } 21 else{ 22 if(f[x][y].x+fx[i]-f[tx][ty].x!=0) return true; 23 if(f[x][y].y+fy[i]-f[tx][ty].y!=0) return true; 24 } 25 } 26 } 27 } 28 return false; 29 } 30 void prvs(){ 31 for(int i=0;i<n;++i)for(int j=0;j<m;++j) 32 f[i][j]=(nds){0,0}; 33 } 34 int main(){ 35 while(scanf("%d%d",&n,&m)!=EOF){ 36 prvs(); 37 for(int i=0;i<n;++i){ 38 scanf("%s",s); 39 for(int j=0;j<m;++j){ 40 if(s[j]=='S'){ 41 sx=i,sy=j; 42 s[j]='.'; 43 } 44 a[i][j]=(s[j]=='.' ? 1 : 0); 45 } 46 } 47 printf("%s\n",(bfs() ? "Yes" : "No")); 48 /*cout<<sx<<" "<<sy<<endl; 49 for(int i=0;i<n;++i){ 50 for(int j=0;j<m;++j) 51 printf("(%d, %d) ",f[i][j].x,f[i][j].y); 52 printf("\n"); 53 }*/ 54 } 55 return 0; 56 }