基础算法学习--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;
- 建议用数组模拟队列,更快且不容易发生段错误。