基础算法学习--dfs和bfs

dfs的模板

注意bool判断是否走过这个点并注意回溯的处理。
注意条件判断和边界问题。

//边界判断即剪枝
if(chk()) return;
if(over(BianJie)) return;

if(bool = false)//未搜索过
  bool = true;
  //赋值或纪录
  dfs(n + 1);
  //复原赋值即回溯
  bool = false;

dfs 小例题

题目
给定一个整数 n,将数字 1∼n 排成一排,将会有很多种排列方法。
现在,请你按照字典序将所有的排列方法输出。

ac代码

#include<iostream>

using namespace std;

const int N  = 1e6;

bool chk[N];
int res[N];
int n;

void dfs (int num){
    if(num == n){
        for(int i = 0; i < num;i ++ ) cout<<res[i]<<' ';
        cout<<endl;
        return;
    }
    
    for(int i = 1;i <= n;i ++){
        if(!chk[i]){
            chk[i] = true;
            
            res[num] = i;
            
            dfs(num + 1);
            
            chk[i] = false;
        }
    }
}

int main(){
    cin >> n;
    
    dfs(0);
    
    return 0;
}

n皇后问题题解

#include<iostream>

using namespace std;

const int N = 20;

int n;
char res[N][N];
bool col[N],dg[N],udg[N];

void dfs(int u){
    if( u == n ){
        for(int i = 0;i <n ;i ++ )puts(res[i]);
        cout<<endl;
        return;
    }
    
    for(int i = 0;i < n;i ++){
        if(!col[i] && !dg[u + i] && !udg[n - u + i]){
            col[i] = dg[u + i] = udg[n - u + i] = 1;
            res[u][i] = 'Q';
            dfs(u + 1);
            col[i] = dg[u + i] = udg[n - u + i] = 0;
            res[u][i] = '.';
        }
    }
}

int main(){
    cin>>n;
    
    for(int i = 0 ;i < n;i ++)
        for(int j = 0;j < n;j ++)
            res[i][j] = '.';
            
    dfs(0);
    
    return 0;
}

bfs模板

#include<iostream>
#include<algorithm>
#include<cstring>

using namespace std;
typedef pair<int,int> p;

const int N = BianJie;

int n ,m;
int M[N][N];
int res[N][N];
p q[N * N];

int bfs(){
     int hh = 0,tt = 0;//模拟的队列的头和尾
     
     memset(res, -1, sizeof res);//初始化为全未走过
     
     res[0][0] = 0;//起始位置走过
     
     q[0] = {0,0};//起始位置入队
     
     int dx[4] = {0,1,-1,0};
     int dy[4] = {1,0,0,-1}; //控制上下左右四个方向
     
     while(hh <= tt){
         auto t = q[hh ++];
         //遍历四个方向
         for(int i = 0 ;i < 4 ;i ++){
             int x = t.first + dx[i];
             int y = t.second + dy[i];
             if(x >= 0 && y >= 0 && x < n && y < m && res[x][y] == -1){
                 res[x][y] = res[t.first][t.second] + 1;
                 q[++ tt] = {x,y};
             }
         }
     }
     
     return res[][];//需要查找的下标
}

bfs的pta例题

题目

7 龙舌兰酒吧 (100 分)
有一个大小为n*m的矩形小镇,城镇上有房屋(“#”表示,无法通过),有空地(“.”表示,可通行),每次移动只能朝上下左右四个方向,且需花费1单位时间。

一天,二乔和承太郎约定在龙舌兰酒吧见面,两人同时从各自所在位置向酒吧出发。请问最少需要过多少时间他们才能在酒吧碰面。

地图上P表示二乔的位置,W表示承太郎的位置,B表示酒吧的位置。

ac代码*

#include<iostream>
#include<cstring>
#include<algorithm>//头文件导入

using namespace std;

const int N = 1010;//为数组大小准备
typedef pair<int,int> p;//pair变量,相当于两个int成员的结构体

int n,m;
int t1,t2;//两个人的时间
int x1,x2,y1,y2;//两个人所在的位置
char M[N][N];//地图
int res[N][N];//j结果记录,从初始位置走到某个点花费的时间
//bfs函数
int bfs(int x3,int y3){
    p q[N * N];//数组模拟队列
    int hh = 0,tt = 0;//hh -- 头,tt -- 屁股
    
    memset(res, -1, sizeof res);//将res所有成员初始化为-1
    
    res[x3][y3] = 0;//-1为未走过,将初始点标记为走过
    
    q[0] = {x3,y3};//初始位置入队
    
    int dx[4] = {-1,0,1,0};
    int dy[4] = {0,1,0,-1};//控制上下左右走向
    //当队列不为空时
    while(hh <= tt){
        auto t = q[hh ++];//取出头元素
        //遍历t位置上下左右的元素
        for(int i = 0;i < 4 ;i ++){
            int x = t.first + dx[i],y = t.second + dy[i];//被检查点的坐标
            //未超出边界,未走过,位置可走
            if(x >= 0 && y >= 0 && x < n && y < m && res[x][y] == -1 && M[x][y] != '#'){
                res[x][y] = res[t.first][t.second] + 1;
                q[++ tt] = {x,y};
                //符合条件,返回时间
                if(M[x][y] == 'B') return res[x][y];
            }
        }
    }
    //上面没有返回数据,走不到指定位置
    return -1;
}

int main(){
    cin>>n>>m;
    //读入地图并记录两人坐标
    for(int i = 0;i < n;i ++){
        for(int j = 0;j < m;j ++){
            cin>>M[i][j];
            if(M[i][j] == 'W') x1 = i,y1 = j;
            if(M[i][j] == 'P') x2 = i,y2 = j;
        }
    }
    //求出时间
    t1 = bfs(x1,y1);
    t2 = bfs(x2,y2);
    
    if(t1 != -1 && t2 != -1) cout<<max(t1,t2);
    else cout<<"-1";
    
    return 0;
}

小tips

  • 当处在第i列第u行时,正对角线下标为u + i,反对角线为n - u + i;
  • 建议用数组模拟队列,更快且不容易发生段错误。
posted @ 2021-04-06 11:10  Xuuxxi  阅读(169)  评论(0)    收藏  举报