cdcq

梦幻小鱼干

导航

【洛谷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 }
View Code

 

posted on 2020-02-05 12:02  cdcq  阅读(268)  评论(0编辑  收藏  举报