zoukankan      html  css  js  c++  java
  • #深搜DFS #宽搜BFS 学习心得20.8.12

    宽搜

    数据结构:队(queue)

    空间:O(2^n),指数级别。

    具有“最短路” 的性质。
    

    框架

    
    定义一个队列 queue q[n];
    bfs{
    
    	while(q不为空){
    		取队头 t;
    		拓展所有与t有关联的元素x;
    		if(x未遍历){
    			x入队;
    			更新x的距离 d[x] = d[t] + 1;
    		}
    		
    		
    	}
    
    }
    
    例题 :ACwing 844. 走迷宫

    给定一个n*m的二维整数数组,用来表示一个迷宫,数组中只包含0或1,其中0表示可以走的路,1表示不可通过的墙壁。

    最初,有一个人位于左上角(1, 1)处,已知该人每次可以向上、下、左、右任意一个方向移动一个位置。

    请问,该人从左上角移动至右下角(n, m)处,至少需要移动多少次。

    数据保证(1, 1)处和(n, m)处的数字为0,且一定至少存在一条通路。

    输入格式
    第一行包含两个整数n和m。

    接下来n行,每行包含m个整数(0或1),表示完整的二维数组迷宫。

    输出格式
    输出一个整数,表示从左上角移动至右下角的最少移动次数。

    数据范围
    1≤n,m≤100
    输入样例:
    5 5
    0 1 0 0 0
    0 1 0 1 0
    0 0 0 0 0
    0 1 1 1 0
    0 0 0 1 0
    输出样例:
    8

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 110;
    typedef pair<int,int> P;
    int m, n;
    int g[N][N] , d[N][N];
    P q[N * N];
    
    int bfs(){
        int  hh = 0 , tt = 0;//* 12
        q[0] = {0, 0};
    
        memset(d, -1, sizeof(d));
        d[0][0] = 0;
    
        int dx[4] = {-1, 1, 0, 0}, dy[4] = {0, 0, -1, 1};// *18
        while(hh <= tt){
            auto t = q[hh ++];//*20
    
            for(int i = 0; i <4; i ++){
                int x = t.first + dx[i], y = t.second + dy[i];// *23
                if(x >= 0 && x < n && y >= 0 && y < m && g[x][y] == 0 && d[x][y] == -1){//*24
                    d[x][y] = d[t.first][t.second] + 1;//*25
                    q[ ++ tt] = {x, y};//*26
                }
    
            }
        }
        return d[n - 1][m - 1];
    }
    
    int main(){
        cin >> n >> m; 
        for(int i = 0;i <n; i ++)
            for(int j = 0 ; j < m; j ++)
                cin >> g[i][j];
        cout << bfs() << endl;
        return 0;
    }
    /*
    *12:  hh tt 表示 栈头和栈尾;
    *18:  上, 下, 左, 右 四个方向;
    *20:  auto 会根据初始化的内容自动定义变量的类型,这句话等价于 "P t = q[hh ++];";
          t是当前所在的点;
    *23:  x, y 表示原来那个点可以走到的点。
    *24:  这个点在地图范围内 且 可以走 且 没有走过的时候;
    *25:  给新的点定义上新的层数, 也就是到起点的最短可行距离;
    *26:  将新的点入栈;
    */
    
    

    深搜

    数据结构: 栈 stack

    空间: O(n)

    框架

    dfs{
    	if(满足条件){
    		按要求干活;
    		return ;回溯
    	}
    	for(枚举){
    		if(找到没有被枚举过的点){
    			按题目干活;
    			记录这个点已被枚举;
    			dfs(这个点);
    			取消记录,恢复现场;(回溯)
    		}	
    	}
    
    }
    
    
    
    例题1 :AcWing 842. 排列数字

    给定一个整数n,将数字1~n排成一排,将会有很多种排列方法。

    现在,请你按照字典序将所有的排列方法输出。

    输入格式
    共一行,包含一个整数n。

    输出格式
    按字典序输出所有排列方案,每个方案占一行。

    数据范围
    1≤n≤7
    输入样例:
    3
    输出样例:
    1 2 3
    1 3 2
    2 1 3
    2 3 1
    3 1 2
    3 2 1

    #include<bits/stdc++.h>
    using namespace std;
    int n, p[10];
    bool b[10];
    void D (int u){
    
        if(u == n){
            for(int j = 0; j < n; j ++ )
                cout << p[j] << " ";
            cout << endl;
            return ;
        }
    
        for(int i = 1; i <= n; i ++)
            if( !b[i] ){
                b[i] = 1;
                p[u] = i;
                D(u + 1);
                b[i] = 0;
            }
        return ;
    }
    int main(){
        cin >> n;
        D(0);
        return 0;
    }
    /*
    i 不可以放在 函数D 的外面定义!
    */
    
    
    例题2 : AcWing 843. n-皇后问题

    n-皇后问题是指将 n 个皇后放在 n∗n 的国际象棋棋盘上,使得皇后不能相互攻击到,即任意两个皇后都不能处于同一行、同一列或同一斜线上。

    现在给定整数n,请你输出所有的满足条件的棋子摆法。

    输入格式
    共一行,包含整数n。

    输出格式
    每个解决方案占n行,每行输出一个长度为n的字符串,用来表示完整的棋盘状态。

    其中”.”表示某一个位置的方格状态为空,”Q”表示某一个位置的方格上摆着皇后。

    每个方案输出完成后,输出一个空行。

    输出方案的顺序任意,只要不重复且没有遗漏即可。

    数据范围
    1≤n≤9
    输入样例:
    4
    输出样例:
    .Q…
    …Q
    Q…
    …Q.

    …Q.
    Q…
    …Q
    .Q…

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 20;
    int n, p[N];
    char g[N][N];
    bool col[N], dg[N], udg[N];
    void D (int u){
    
        if(u == n){
            for(int j = 0; j < n; j ++ )
                puts(g[j]);
            cout << endl;
            return ;
        }
    
        for(int i = 0; i < n; i ++)
            if( !col[i] && !dg[u + i] && !udg[n - u + i] ){
                g[u][i] = 'Q';
                col[i] = dg[u + i] = udg[n - u + i] = 1;
                p[u] = i;
                D(u + 1);
                g[u][i] = '.';
                col[i] = dg[u + i] = udg[n - u + i] = 0;
            }
        return ;
    }
    int main(){
        cin >> n;
        for(int i = 0; i < n; i ++)
            for(int j = 0; j < n; j ++)
                g[i][j] = '.';
        D(0);
        return 0;
    }
    /*
    *0 搜索方式 : 深搜。
        具体操作:先遍历 第0行 可以放皇后的所有位置,再遍历 第1行 可以放皇后的位置...依次类推到 第n行。
    
    *1 
        补英文:column   列
                diagonal 对角线
                row      行
    *2 这里 u+i  以及  n-u+i  分别是  (u,i)所在的对角线(这样的 /)  以及  反对角线(这样的 )
        具体推导是: 令 (u, i) 为 在坐标轴上的 (x, y);
                    (x, y)分别在对角线 y = x + b 以及 反对角线 y = -x + b 上。
                    坐标轴上的 y=x+b  =>  b=x-y  =>  b=n+x-y  (防止出现负数) ;
                          以及  y=-x+b  =>  b=x+y 。
    
                    这时的 b 就是 (u,i) 所在的 对角线(或反对角线)的唯一编号;
                    这样下来,在同一对角线的所有点就有了一样的唯一编号。(具体多少不重要u, i 可调换)
    *3 p[u] 表示第u 行放的皇后的位置。
    *4 时间是 18ms 左右;
    */
    
    /*
        *2点中说的对角线上的 u, i 调换对比版,答案是一样的。
        不用纠结 对角线和反对角线 这里的坐标序号之类的。
    #include<bits/stdc++.h>
    using namespace std;
    const int N = 20;
    int n, p[N];
    char g[N][N];
    bool col[N], dg[N], udg[N];
    void D (int u){
    
        if(u == n){
            for(int j = 0; j < n; j ++ )
                puts(g[j]);
            cout << endl;
            return ;
        }
    
        for(int i = 0; i < n; i ++)
            if( !col[i] && !dg[i + u] && !udg[n - i + u] ){
                g[u][i] = 'Q';
                col[i] = dg[i + u] = udg[n - i + u] = 1;
                p[u] = i;
                D(u + 1);
                g[u][i] = '.';
                col[i] = dg[i + u] = udg[n - i + u] = 0;
            }
        return ;
    }
    int main(){
        cin >> n;
        for(int i = 0; i < n; i ++)
            for(int j = 0; j < n; j ++)
                g[i][j] = '.';
        D(0);
        return 0;
    }
    
    */
    /*
    原始的 “选与不选”搜索方法;
    从(0,0) 一直依次遍历到 (n,n),对于每一个格子的操作是(放皇后或不放皇后);
    时间是 107ms左右 ,不如上一个算法;
    #include<bits/stdc++.h>
    using namespace std;
    const int N = 20;
    int n ;
    char g[N][N];
    bool col[N], dg[N], udg[N], row[N];
    void D (int x, int y, int s){
        if(y == n){
            x ++;
            y = 0;
        }
    
        if(x == n){
            if(s == n){
                for(int i = 0; i < n; i ++)
                    puts(g[i]);
                    cout << endl;
            }
            return ;
        }
    
        D(x, y  + 1, s);
    
        if(!row[x] && !col[y] && !dg[n - x + y] && !udg[x + y]){
            row[x] = col[y] = dg[n - x + y] = udg[x + y] = 1;
            g[x][y] = 'Q';
            D(x, y + 1, s + 1);
            g[x][y] = '.';
            row[x] = col[y] = dg[n - x + y] = udg[x + y] = 0;
        }
    }
    int main(){
        cin >> n;
        for(int i = 0; i < n; i ++)
            for(int j = 0; j < n; j ++)
                g[i][j] = '.';
        D(0, 0, 0);
        return 0;
    }
    */
    
    
  • 相关阅读:
    查看linux服务器CPU相关
    Innobackupex(xtrabackup)物理备份
    给xen虚拟机添加硬盘分区格式化
    快速做ssh免密钥登陆
    windows基本命令大全
    linux系统下python升级安装
    快速安装Java环境
    「十二省联考 2019」骗分过样例
    「十二省联考 2019」皮配
    「SNOI2019」积木
  • 原文地址:https://www.cnblogs.com/yuanyulin/p/14026761.html
Copyright © 2011-2022 走看看