深搜dfs+广搜bfs+树与图的遍历+拓扑序列(模板篇acwing)

目录

深度优先搜索dfs:

例题:排列数字

例题:n-皇后问题

广度优先搜索bfs:

例题:走迷宫

树和图的遍历:

树和图的存储:

有向图:

 邻接表:

树和图的遍历:

例题:树的重心

例题:图中点的层次

拓扑序列

 例题:有向图的拓扑序列


深度优先搜索dfs:

实现数据结构:stack栈

特点:不撞南墙不回头

空间 :O(h)(h表示树的高度)

不具备最短路

例题:排列数字

问题:

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

输入样例:3

输出样例:
0 1 2
0 2 1
1 0 2
1 2 0
2 0 1
2 1 0

模拟过程:

注意模拟不撞南墙不回头这个思想:

我们从第0层开始向下搜索:即dfs(0),一开始的st[N]数组都是为0的(全局变量不初始化,默认为0),那么我们的第0层就按照for循环的顺序填上path[0]=0,并将0标记为1,表示已经用过了,后面不能再使用了,接下来,我们搜索下一层:即dfs(u+1),此时要注意并不是马上就执行st[i]=0这个操作,而是重新开始执行函数,此时参数为u+1,同样的,还是进入for循环,此时因为已经标记了0,所以0不满足条件,下一个则是1,所以在第一层填上1,至此path已经填好了path[0]=0 path[1]=1 ,接下来重复操作则有path[2]=2

path[2]=2的下一步时dfs(u+1),注意此时u==n,可以执行第一个if语句了,将我们的path数组n大小之前的数输出【0 1 2】并且return回溯

回溯:返回到调用这次递归前的那一层,也就是我们填入path[2]=2的那一层,即第二层:也就是说那一层我们已经执行完了,dfs(u+1)这个操作,按照顺序我们要执行st[i]=0,此时的i很明显是2,相当于我们用了2,在搜索下一层时,我们先标记2不能用,在它搜索回来时,我们将2取消标记

再次for循环:按照for循环的顺序,由于2已经用了,虽然它回来时解除了标记,但是我们已经用不到了,因为i++,导致现在i的值是3,然后我们将3填入path,即此时为path[2]=3,意味着我们的第二层又增加了一个组合:【0,1,3】,相当于碰到底后返回,并且向另外一个分支走去,这就是dfs!

#include<iostream>
using namespace std;

const int N=10;
int n;
int path[N];//存放答案
bool st[N];//标记该元素是否被使用过

void dfs(int u)
{
    if(u==n)//当遍历到最后一层时,输出该层
    {
        for(int i=0;i<n;i++) printf("%d ",path[i]);
        printf("\n");
    	return;//回溯
    }
    for(int i=0;i<n;i++)
    {
        if(!st[i])//如果该元素没有被使用过,那么就使用该元素
        {
            path[u]=i;//存储
            st[i]=1;//true标记为已经用过了
            dfs(u+1);//向下一层进行搜索
            st[i]=0;//回复现场
        }
    }
}
int main()
{
	cin>>n;
    dfs(0);
}

例题:n-皇后问题

问题:

n-皇后问题是指将 n 个皇后放在 n∗n 的国际象棋棋盘上,使得皇后不能相互攻击到,即任意两个皇后都不能处于同一行、同一列或同一斜线上。

现在给定整数n,请你输出所有的满足条件的棋子摆法。

 输入样例:4

输出样例:

.Q..
...Q
Q...
..Q.

..Q.
Q...
...Q
.Q..

思路解析:

因为每行每列每一斜线都只能放置一个皇后,那么我么就需要三个数组来判断这个位置是否能放置数组:即列数组,正对角线数组,反对角线数组

问题:为什么不是用四个数组来判断?为什么没有行数组?

答:像上题一样,我们是一层层的判断,每一层的一种情况,我们只放置一个数,那么就确保了:每一行只会有一个元素,所以不需要再开一个行数组进行判断

模拟过程:

整体与上面的排列数字一样,多加了一个mp[u][i]='.'的操作,也就是说我回溯回来的时候,证明了这个点的放置是与其他点有冲突的,所以需要重新将已排好的点再次赋值成原始的模样,有一种天然的对称关系^ ^

#include<iostream>
using namespace std;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值