1. 深度优先搜索算法的概念:
深度优先搜索属于图算法的一种,英文缩写为DFS(Depth First Search.)其过程简要来说是对每一个可能的分支路径深入到不能再深入为止,而且每个节点只能访问一次。
DFS适合此类题目:给定初始状态跟目标状态,要求判断从初始状态到目标状态是否有解。
2、原理详解
(深度优先搜索用栈(stack)来实现,整个过程可以想象成一个倒立的树形)
1、把根节点压入栈中。
2、每次从栈中弹出一个元素,搜索所有在它下一级的元素,把这些元素压入栈中。并把这个元素记为它下一级元素的前驱。
3、找到所要找的元素时结束程序。
4、如果遍历整个树还没有找到,结束程序。
3.深度优先搜索基础模板
void dfs(int k)
{
if(满足输出条件)
{
输出解;
}
for(int i=1;i<=尝试方法数;i++)//遍历所有可能
if(满足情况的话)
{
为进一步搜索标记一下;
dfs(k+1);
回溯;
}
}
基本例题
洛谷 p1706 全排列问题
题目描述
输出自然数 1 到 n 所有不重复的排列,即 n的全排列,要求所产生的任一数字序列中不允许出现重复的数字。
输入格式
一个整数 n。
输出格式
由 1∼n 组成的所有不重复的数字序列,每行一个序列。
每个数字保留 5个场宽。
输入输出样例
输入
3
输出
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
说明/提示 1≤n≤9
//这是一道最基本的深搜模板题,入门必备,直接上代码
//差不多可以直接根据上面那个基本模板直接套
#define isc(x) scanf("%d",&x)
#define ipr(z) printf("%d\n",z)
#define mem(x,y) memset(x,y,sizeof(x))
#include<bits/stdc++.h> //万能头文件
#include<algorithm>
typedef long long ll;
using namespace std;
inline void read(long long int &num){ //快读
int s = 0, w = 1; char ch = getchar();
while(ch < '0' || ch > '9'){ if(ch == '-') w = -1; ch = getchar(); }
while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
num = s*w;}
int a[100],vis[100],n;
void dfs(int k)
{
if(k==n+1) //满足输出条件后直接输出
{
for(int i=1;i <=n;i ++)
cout<<" "<<a[i];//5个宽字符
cout<<endl;
return;
}
for(int j=1;j <=n;j ++)//开始遍历
{
if(vis[j]==0){ //判断是否满足条件
a[k] =j;
vis[j] =1;
dfs(k+1); //继续搜索
vis[j] =0;//回溯
}
}
}
int main()
{
cin>>n;
dfs(1);
return 0;
}
洛谷P1157 组合的输出
也是一道基本的深搜模板题 与上一道相比 只是要在判断条件的时候注意一下就行了
本质上和上一道题是一样的 直接上代码了 说多了也没意思
#define isc(x) scanf("%d",&x)
#define ipr(z) printf("%d\n",z)
#define mem(x,y) memset(x,y,sizeof(x))
#include<bits/stdc++.h> //万能头文件
#include<algorithm>
typedef long long ll;
using namespace std;
int h[100],w[100];
int n,r;
void dfs(int k){
if(k==r+1)
{
for(int i=1;i <=r;i ++)
if(h[i]>=10)
cout<<" "<<h[i];
else
cout<<" "<<h[i];
cout<<endl;
return;
}
for(int i=1;i <=n;i ++)
{
if(w[i]==0&&h[k-1]<i){ //多了一个条件判断,也没啥东西了
h[k] =i;
w[i] =1;
dfs(k+1);
w[i] =0;
}
}
}
int main()
{
cin>>n>>r;
dfs(1);
return 0;
}
//会了这两道题(其实也算是一道)再去看看深搜的概念,模型演示啥的,也就基本入门了,也就可以向难一点的题发出挑战了
P1219 [USACO1.5]八皇后 Checker Challenge
题目描述
一个如下的 6×6 的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行、每列有且只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子。
上面的布局可以用序列 2 4 6 1 3 5 来描述,第 ii 个数字表示在第 ii 行的相应位置有一个棋子,如下:
行号 1 2 3 4 5 6
列号 2 4 6 1 3 5
这只是棋子放置的一个解。请编一个程序找出所有棋子放置的解。
并把它们以上面的序列方法输出,解按字典顺序排列。
请输出前 3 个解。最后一行是解的总个数。
输入格式
一行一个正整数 n,表示棋盘是 n×n 大小的。
输出格式
前三行为前三个解,每个解的两个数字之间用一个空格隔开。第四行只有一个数字,表示解的总数。
输入输出样例
输入
6
输出
2 4 6 1 3 5
3 6 2 5 1 4
4 1 5 2 6 3
4
//还是根据代码来说吧 好理解一点 来人 上代码
//其实还是一样的 先根据基本模板来搞 只不过会加上一些判断条件和根据题意加上一些东西
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
int h[14],k[3][27]={0},n,sum=0;
void dfs(int i){
if(i>n){ //当条件满足的时候 也就是说明搜完一次了
sum ++; //总次数要加一
if(sum>3){ //只输3行
return;
}
for(int t=1;t <=n;t ++)
cout<<h[t]<<" ";
cout<<endl;
return ;
}
for(int j=1;j <=n;j ++){ //还是遍历
if((!k[0][j])&&(!k[1][i+j])&&(!k[2][i-j+n])){
/*判断条件,因为是根据每一行来开始搜的 所以不用考虑行上会有两个棋子
只需要考虑每列和两条对角线上是否有棋子就可以了,而你可以发现左上到右下的对角线的每个棋子的列号减行号的值是固定的 但要考虑可能为负数的情况所以要+n 从右上到左下的对角线也是一样的 他们行号和列号的和的值是一定的 开个2维数组分别标记就可以了*/
k[0][j] =1; k[1][i+j] =1; k[2][i-j+n] =1;
h[i] = j;
dfs(i+1); //继续搜索
k[0][j] =0; k[1][i+j] =0; k[2][i-j+n] =0; //回溯
}
}
}
int main()
{
cin>>n;
dfs(1);
cout<<sum<<endl;
return 0;
}
好吧 由于本人是一个蒟蒻,有些不足的地方欢迎大佬指正
葱葱葱
本文介绍了深度优先搜索算法的基本概念和原理,通过洛谷上的三道题目——全排列问题、组合的输出和八皇后问题,展示了深度优先搜索的应用。提供了解题思路和基础模板,适合初学者入门和进阶。

6961

被折叠的 条评论
为什么被折叠?



