一、DFS是什么?
DFS英文全名:Depth First Search;中文名:深度优先算法。DFS是一种早期爬虫使用的常用方法。如今广泛应用于解决数学、游戏等生活问题,例如全排列,组合、迷宫等。
二、原理
DFS原理很简单,举个简单例子。你去找你的同事,他住在一栋5层的房屋里的其中一个房间,但你不知道他在哪个房间,那么你首先就从一楼一个一个房间的找,看他在不在一楼,如果不在一楼,那么就去二楼找。以此类推,你最终会找到他身在哪个房间。这就是DFS的原理(个人拙见)。
三、DFS的使用
1.DFS模板
伪代码如下(示例):
#include<stdio.h>
int check(~~~)
{
//检查部分
if(~~~)
return 0; //不符合要求
return 1; //符合要求
}
void dfs(int i)
{
//判断是否出界
if(~~~)
{
return;
}
//填数部分
for(~~~~)
{
//检查
if(!check(~~))
{
//代码~~~
continue;
}
//符合要求
dfs(i+1);
//回溯
//代码~~~
}
return; //来到这里,dfs搜索结束
}
int main()
{
dfs(i); //i代表层数
return 0;
}
2.使用DFS的几个小例子
(1).全排列
//想必大家高中时期都有学习全排列的知识吧!!!
三个数字(1,2.,3)的全排列有多少种呢?
答案是:321=6种,分别是:123、132、213、231、312、321.
那我们怎么用代码实现呢?话多不说上代码!
#include<iostream>
using namespace std;
int a[3] = { 0 }; //存储数字1、2、3
int target = 0; //记录排列总数
int k = 0;
bool check(int b) {
//检查
int aa = 0;
for (int i = 0; i < 3; i++) {
if (a[i] == b) {
//每次数组中有与b相同的数字时,aa就加1
aa++;
}
}
//如果aa大于1,就说明不符合要求,
//即b被使用了两次,也就是说数组
//a[]中有两个b,返回false
if (aa > 1) return false;
return true;
}
void dfs(int k)
{
//1.跟检查是否越界类似
if (target == 3) {
//当target等于3时,说明已经排列完成,
//我们把它输出
for (int i = 0; i < 3; i++)
printf("%d", a[i]);
printf("\n");
return;
}
//2.填数
for (int i = 1; i < 4; i++) {
//赋值
a[k] = i;
if (!check(a[k])) {
//不符合要求,我们把它重新赋值为0
a[k] = 0;
//并且跳出此次循环
//这里要注意用的是continue,
//不要用了return,我第一次写的时候
//就用了return,结果找了我一下午,
//希望大家别像我一样啊!!!
continue;
}
target++; //加一代表数组填数成功,走到这说明前面都成功啦
dfs(++k); //接着我们进入下一层
//回溯,这一段要多多体会哦,不懂就多看几遍!
k--;
a[k] = 0;
target--;
}
return; //dfs搜索结束
}
int main()
{
dfs(k);
return 0;
}
运行结果
(2).判断素数
我们来找一下1-100中的素数个数。
//2.判断素数+dfs
#include<iostream>
#include<math.h>
using namespace std;
int a[101] = { 1,1 }; //记录100以内(1-100)是素数的数字,赋为0,非素数为1
int k = 2; //dfs层数标记
int sum = 0; //记录100以内的素数总数
void dfs(int k) {
//判断是否出界
if (k > 100) return;
for (int i = 2; i <= sqrt(k); i++)
{
if (k % i == 0) a[k] = 1;
}
dfs(++k);
}
int main()
{
dfs(k);
for (int i = 0; i < 100; i++)
{
if (a[i] == 0) {
sum++;
cout << i <<endl;
}
}
cout << endl;
cout << sum << endl;
return 0;
}
运行结果
(3).组合问题
我们选取1-9其中的5个数字的进行排列。
//组合问题(1-10中选出5个组成组合)
#include<iostream>
using namespace std;
int a[5] = { 0 }; //存储由1-9形成的组合
int k = 0; //dfs层数
int target = 0; //记录已经排列的数字的数目
int sum = 0;
bool check(int b)
{
int aa = 0;
for (int i = 0; i < 5; i++)
{
if (a[i] == b) aa++;
if (aa > 1) return false;
}
return true;
}
void dfs(int k)
{
//判断是否完成组合
if (target == 5)
{
for (int i = 0; i < 5; i++)
{
cout << a[i];
}
cout << endl;
sum++;
return;
}
//填数
for (int i = 1; i < 10; i++)
{
a[k] = i;
if (!check(i))
{
a[k] = 0;
continue;
}
target++;
dfs(++k);
//回溯
target--;
a[k--] = 0;
}
}
int main()
{
dfs(k);
cout << "sum="<<sum;
return 0;
}
运行结果
3.升阶DFS使用
我们来提升一下难度,嘻嘻,新手可能会有点难度哦!不多多看几次就行啦!
(1).八皇后
我们就举例一下经典中的经典吧!
题目链接:八皇后题目链接
代码呈上!!!:
#include<iostream>
using namespace std;
int row[14] = { 0 };
int line[14] = { 0 };
int zhudui[100] = { 0 };
int fudui[100] = { 0 };
int sum = 0;
int i = 1;
int n;
bool check(int i,int j)
{
//检查是否符合要求
if (row[j] || zhudui[j - i + n] || fudui[j + i])
{
return false;
}
return true;
}
void dfs(int i)
{
//出界并输出
if (i > n)
{
sum++;
if(sum<=3)
{
for (int j = 1; j <= n; j++)
{
cout << line[j];
}
printf("\n");
}
return;
}
//填数
for (int j = 1; j <= n; j++)
{
if (!check(i, j))
{
continue;
}
row[j] = 1;
line[i] = j;
zhudui[j - i + n] = 1;
fudui[j + i] = 1;
dfs(i+1);
//回溯
row[j] = 0;
zhudui[j - i + n] = 0;
fudui[j + i] = 0;
}
return;
}
int main()
{
cin >> n;
dfs(i);
cout << sum << endl;
return 0;
}
代码运行结果:
四、总结
dfs的原理很简单、代码也很简洁,但是其中蕴含的内容却对新人来说有点绕,我们需要多多理解、多多整理思路。如果你想成为算法大师,这是必过的一道坎!加油吧!程序猿!!!
五、最后
这是我第一次写优快云,有不对的地方希望大家多多包涵!有问题可以告诉我。希望这篇文章对大家能有所帮助。谢谢啦!