关于深度优先遍历算法-c++语言

深度优先遍历及例题加讲解

竞赛里面重要算法,全当学习笔记啦。(如有不足多多谅解)

零、什么是深度优先遍历

深度优先遍历简称DFS(Depth First Search)。
我们简单的举个栗子:
从前有位首富打野,一共14个打野点,首富从1号打野点开始,要打遍所有野区,可以有什么样的打野路线呢?
在这里插入图片描述
我们假设挑一个方向打野打到底,我们选择一条支路,尽可能不断深入,如果遇到死路就往回退,回退过程中如果遇到没打过的野怪就进入这条支路继续深入打野。

在图中,我们先从1号点,到2号一直道6号(蛤蟆)。这个时候发现已经是个死胡同了,不能再往前走了(男枪:懂事的打野已经去上路假装gank,再吃波兵线)
在这里插入图片描述
于是,我们退回到五号打野点,然后往8号点走,然后又无路可走了,于是退回到2号点,沿着2号点方向打野即探索2-12-13-14
在这里插入图片描述
按照这个思路,我们探索完2号点方向,就退回到1号点向其他没有打过野的方向探索。
像这样先深入探索,走到头再退回寻找其他出路的遍历方式,就叫做深度优先搜索。

二、深度优先遍历例题

(一)对数字全排列相关问题

1.题目:
对数字1-9进行全排列,求出1-9全排列有多少种。

2.基础深度优先遍历例题。

3.解题代码:

//用dfs解决1-9的全排列个数问题 

#include<bits/stdc++.h>
using namespace std;
int total=0;//用于计数 
int check[10]={0};//检查当前数字有没有用过,用过了就标记为1,也可以用bool类型 
int lista[10]={0};//用于存储排列结果 
void dfs(int step){
	if(step==10){
		total++;
		/*  显示排列结果 
		for(int j=1;j<=9;j++){
			cout<<lista[j];
		} 
		*/
		return;
	}
	for(int i=1;i<=9;i++){ //1-9个数字循环 
		if(check[i]==0){
			check[i]=1;  //当前i这个数字用过,标记为1; 
			lista[step]=i;//存储结果 
			dfs(step+1);//进行下一个位置的数字选择 
			check[i]=0;//将用过的数字再标记为0,再使用; 
		}
		
	}
} 
int main(){
	dfs(1);
	cout<<total;
}

同样的也可以用c++的一个函数直接求解,如下:


```cpp
//用next_permutation函数进行全排列(升序)
//需要头文件#include<algorithm> 

#include<bits/stdc++.h>
using namespace std;
int main(){
	int a[10]={1,2,3,4,5,6,7,8,9};
	int cnt=0;
	do{
		cnt++;
	}while(next_permutation(a,a+9));
	cout<<cnt;
}

4.稍微进阶一点的题目:
1-9数字对应着a-9个字母,使得ab+cd+ef+gh+i=141,问有多少种可能?
这题仅仅在原有基础上,添加一些限制条件。
代码:

#include<bits/stdc++.h>
using namespace std;
int total=0;//用于计数 
int check[10]={0};//检查当前数字有没有用过,用过了就标记为1,也可以用bool类型 
int lista[10]={0};//用于存储排列结果 
int cnt=0;

bool checka(){//使用布尔类型进行结果检测 
	int t=lista[1]*lista[2]+lista[3]*lista[4]+lista[5]*lista[6]+lista[7]*lista[8]+lista[9];
	if(t==141){
		return true;
	}
	return false;
}

void dfs(int step){
	int t=0;
	if(step==10){
		//total++;
		/*  显示排列结果 
		for(int j=1;j<=9;j++){
			cout<<lista[j];
		} 
		*/
	if(checka()){//调用布尔类型,得出符合结果加一。 
		cnt++;
	} 
	
		return;
	}
	for(int i=1;i<=9;i++){ //1-9个数字循环 
		if(check[i]==0){
			check[i]=1;  //当前i这个数字用过,标记为1; 
			lista[step]=i;//存储结果 
			dfs(step+1);//进行下一个位置的数字选择 
			check[i]=0;//将用过的数字再标记为0,再使用; 
		}
		
	}
} 
int main(){
	dfs(1);
	cout<<cnt;
}

(二)对地图路径种类问题
1.题目:
如下地图,0的位置可以走,1的位置是路障不能走,问从左上角到右下角有多少种走法?

 0,00,100,10,000,00,110,10,00.

2.深度优先遍历简单例题,从左上角开始,先深入走一遍,不通或者到达了就返回再走另一个方向。
3.解题代码:

 #include<bits/stdc++.h>
using namespace std;
int check[5][6]={0};//检查当前地点有没有走过,走过为1;
int mape[5][6]={
	0,0,0,0,0,0,
	0,0,0,0,1,0,
	0,0,1,0,0,0,
	0,0,0,0,1,1,
	0,0,1,0,0,0,

};
int x[4]={0,1,0,-1};//决定走的方向
int y[4]={1,0,-1,0};
int total=0;
void dfs(int xx,int yy){
	check[1][1]=1;
	int tx=1,ty=1;
	if(xx==4&&yy==5){//到达目的地,计数加一
		total++;
		return ;
	}
	for(int i=0;i<4;i++){
		
		tx=xx+x[i];
		ty=yy+y[i];
		if(tx<1||tx>5||ty<1||ty>6)continue;//不能超过边界
		if(check[tx][ty]==0&&mape[tx][ty]==0){
			check[tx][ty]=1;
			dfs(tx,ty);
			check[tx][ty]=0;
		}
		
		
	}
}
int main(){
	dfs(1,1);
	cout<<total;
}

4.八皇后问题:
有六位皇后,在一个6x6的表格中,有六个皇后,为了让他们不互相攻击(不在同一行同一列同一斜方向),请给她们安排位置。
如下图:
在这里插入图片描述
经典八皇后问题,关键点在于限制条件:不在一个列,不在一个斜线,
不在一个列用checklie[j]=0;然而不在一个斜线则发现行号x与列号j之间的关系:
x+j与x-j+6是固定值即:checkxie[x+j]=0;checkxie2[x-j+6]=0;
解题代码:

#include<bits/stdc++.h>
using namespace std;
int checklie[100]={0};//判断当前列有没有用过 
int checkxie[100]={0};//判断右上和左下的那条斜线有没有用过 
int checkxie2[100]={0};//判断左上和右下的那条斜线有没有用过 
int total=0;//记录结果数 
void dfs(int x){ //x当前行数 
	if(x==7){//当前x=7是结束,结果加一 
		total++;
		return;
	} 
	for(int i=1;i<=6;i++){
		if(checklie[i]==0&&checkxie[x+i]==0&&checkxie2[x-i+6]==0){//判断 
			checklie[i]=1;
			checkxie[x+i]=1;
			checkxie2[x-i+6]=1;
			dfs(x+1);//继续深搜下一行 
			checklie[i]=0;//回溯 
			checkxie[x+i]=0;
			checkxie2[x-i+6]=0;
		}
	}
}
int main(){
	dfs(1);
	cout<<total;
}
  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值