zoukankan      html  css  js  c++  java
  • 【洛谷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
    ",(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("
    ");
    53         }*/
    54     }
    55     return 0;
    56 }
    View Code
  • 相关阅读:
    HTML浏览器标题栏如何设置
    阿里团队常用的布局——双飞翼布局
    浏览器兼容性问题——IE不支持却很实用的CSS属性Outline和Child
    css选择器:基本选择器
    编程十年
    解决WX-IOS打开公众号网页出现的底部导航条
    Angular6路由复用与延迟加载的冲突解决——看看有备无患
    Ionic2 + Angular4 + JSSDK开发中的若干问题汇总
    [Linq Expression]练习自己写绑定
    [Linq To Sql]解决join时的Collation冲突
  • 原文地址:https://www.cnblogs.com/cdcq/p/12263099.html
Copyright © 2011-2022 走看看