• 关于BFS


        Emmmm ,本着不再发明轮子的原则,网上BFS教程一搜一大堆,所以原理就不再讲了,给出几道题加深理解好了>_<

    (不喜欢看博客的看书也行)

    1,

    • 给你一个n*n的0/1矩阵
    • 问完全被1包围的0有多少个(包围的定义类似于围棋)
    • n <= 1000 ;

    (请先自己思考再往下翻)

      SOL :

      其实思路很简单,只要从边界处的0开始广搜,能搜到的都变为1,最后剩下的零就是被1完全包围的

    2,

    • 给你一个n*n的0/1矩阵
    • 不同位置之间的移动规则是相邻(上下左右)且亦或值为1(就是一个是1一个是0)。
    • 给你m个询问,每个询问为一个二元组(x,y),问从点(x,y)最多可以到达几个点(包括自身)。
    • n ≤ 1000, m ≤ 100000 ;

    (请先自己思考)

      SOL :

       首先这明显是广搜题,但如果我们每个询问都去广搜一遍的话复杂度最坏是O(n^2*m)的,显然不行对吧。。

       其实我们可以预处理联通块,然后把联通块内的坐标的答案值记录为所属联通块大小,然后按询问回答即可

       这样的话预处理是O(n^2),询问是O(m),总复杂度就是O(n^2+m)

    3,


      这道题题目较复杂,我发个网址:https://www.luogu.org/problemnew/show/P1126

       SOL:

       首先,由于机器人走的格子与障碍物防止格子并不相同,所以我们要把障碍物从原坐标转化为机器人所走格子的坐标

       然后我们考虑这道题,因为与方向有关,所以我们在广搜时要多加一个参数——方向,也就是说队列中记录的是一个状态(包括横纵坐标和方向)。

       接着层层向外扩展,直到状态横纵坐标与终点横纵坐标相等即可

     这道题较为经典,附上代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    using namespace std;
    const int N = 50 + 2 ;
    
    const int dx[]={-1,-1,0,0} ;
    const int dy[]={-1,0,-1,0} ;
    
    const int cx[]={0,-1,0,1} ;
    const int cy[]={-1,0,1,0} ;
    
    inline int read()
    {
        int k = 0 , f = 1 ; char c = getchar() ;
        for( ; !isdigit(c) ; c = getchar())
          if(c == '-') f = -1 ;
        for( ; isdigit(c) ; c = getchar())
          k = k*10 + c-'0' ;
        return k*f ;
    }
    
    struct node {
        int x,y,d ; int ti ;
    }a,b,c ;
    queue<node>q ;
    
    int n,m ; int sx,sy,ex,ey,sd ; char dd ;
    bool gg[N][N], hh[N][N] ;
    bool vis[11000] ;
    
    inline int fun(node s) {  // 把每种状态转化成一个独一无二的数,记录该状态有没有被访问过 
        return s.d*2600 + s.x*50 + s.y ;
    }
    
    int main()
    {
        n = read() ; m = read() ;
        int xx, yy ;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++) {
                gg[i][j] = read() ;
                if(gg[i][j])
                 for(int k=0;k<4;k++) {  // 把障碍物影响到的点映射到机器人所走坐标 
                    xx = i + dx[k] ; yy = j + dy[k] ;
                    if(xx < 1 || yy < 1 || xx >= n || yy >= m) continue ; // 因为靠墙的位置走不了,所以机器人所走矩形为(n-1)*(m-1) 
                    hh[xx][yy] = 1 ;
                 }
            }
        sx = read() ; sy = read() ; ex = read() ; ey = read() ;
        if(hh[sx][sy] || hh[ex][ey]) {
            printf("-1") ; return 0 ;
        }
        cin>>dd ;
        switch(dd) { // 0-3分别表示 左,上,右,下 
            case 'W' : sd = 0 ;
              break ;
            case 'N' : sd = 1 ;
              break ;
            case 'E' : sd = 2 ;
              break ;
            case 'S' : sd = 3 ;
              break ;
        }
        a.x = sx ; a.y = sy ; a.d = sd ; a.ti = 0 ;
        q.push(a) ; vis[fun(a)] = 1 ;
        while(!q.empty()) {
            a = q.front() ; q.pop() ;
            if(a.x == ex && a.y == ey) {
                printf("%d",a.ti) ;
                return 0 ;
            }
            a.ti ++ ;
            a.d = (a.d + 1) % 4 ;
            if(!vis[fun(a)]){
                q.push(a) ; vis[fun(a)] = 1 ;
            }
            a.d = (a.d + 2) % 4 ; // 减2加2模4意义下相同,为防止出现负数就写成+2 
            if(!vis[fun(a)]) {
                q.push(a) ; vis[fun(a)] = 1 ;
            } 
            a.d = (a.d + 1) % 4 ; // 回到原来方向 
            for(int i=1;i<=3;i++) {
                a.x += cx[a.d] ; a.y += cy[a.d] ;
                if(a.x < 1 || a.y < 1 || a.x >= n || a.y >= m) break ;
                if(hh[a.x][a.y]) break ;
                if(vis[fun(a)]) continue ;
                q.push(a) ; vis[fun(a)] = 1 ;
            }
        }
        printf("-1") ;
        return 0 ;
    }

    我的坐标转化方式:

    (暂完,以后遇到题可能还会更) 

  • 相关阅读:
    生成建表脚本(V2.0)
    QQ抢车位游戏PhysicalDataModel
    自定义工资公式设计
    .NET开发人员必知的八个网站
    MongoDB 学习 error以及解决方法
    lm_sensors 查看硬件信息
    setuid on shell scripts
    SSD寿命状态检测
    SysBench安装使用。
    用rsync对网站进行镜像备份(不靠谱)
  • 原文地址:https://www.cnblogs.com/zub23333/p/8443262.html
Copyright © 2020-2023  润新知