收到学弟的催更,小透明佛系博主来更新一下。
做这道题之前呢,我们需要先了解图的存储(可以用三个数组,一个变量去存储,也可以用队列,栈去存储,看个人怎么用),深度优先搜索(就是一列一列地搜索,类似于递归)和宽度优先搜索(就是一层层地遍历)。
这里应该放一篇我自己写到深搜和广搜的解释的推文,但是我没有,后期有空补一篇
首先,这道题的大概思路就是先存储数到图中,然后深搜,再然后广搜一次。
听起来思路很简单理解。
下面可是正式操作:
一、存数
我们可以开一个栈数组来存储数,然后开一个bool数组来标记是否被访问过,访问过就改为true,没访问前全初始化为false,也就是0。
写一个专门存数的函数,将数字都存入这个栈数组的同时做一下升序排列,也就是按照从小到大一步步排序。(为什么要从小到大,因为题目给的例子就是这样的,从1起始)
存入后呢,就可以开始深搜和广搜了。
二、深搜
深搜是沿着树的深度遍历树的节点,尽可能深的搜索树的分支。
(一条路走到黑,不撞南墙不回头的那种感觉)
比如从1开始,找到了1的左子树2,紧接着继续找2的左子树3,再找3的左子树,一直找下去,直到没有分支了再返回到最近分支的地方。
思路其实跟递归是一样的。
在函数里调用自身。
把递归的思想放到深搜就很好理解了,先找第一个根节点1,然后开始找它的子树,找到后再找子树的子树
然后就可以按照思路写出dfs()函数的写代码啦!
不过要注意的是,
遍历过的数不能再遍历,所以要设置如果vis[v]==false才能进入,才能取值
devC++的编译器的语言标准要换成ISOC++11才能运行for(int v :edge[u]),因为这个写法是 C++11 引入的范围基于的 for 循环(range-based for loop)的。其他语言标准用这个就会编译错误,这种语法用于简化遍历容器(如数组、向量等)或其他可迭代对象的操作,很简洁,明了。
三、广搜
广搜,属于一种盲目搜寻法,目的是系统地展开并检查图中的所有节点,遇到每一层都搜索完这一场的所有值,再去下一层搜索,以找寻结果。换句话说,它并不考虑结果的可能位置,彻底地搜索整张图,直到找到结果为止。
比如1是根节点,1的左右子树分别是2,3,而2的左右子树是4,5。
广搜就是先从初始节点1开始,然后遍历2和同2都在同一深度的3,遍历完这个深度再往下继续遍历。
所以需要一个容器去存储从左到右的所有值,然后遍历完一层就可以从容器最开始进入的数继续遍历,进入后再删去。
需要一个先进先出的容器,
是什么呢?
当然是队列啦!!
就是用队列去存储每一层遍历到的数,一层循环结束就取出队头元素存储,再删除已取出的元素,然后开始取出的这个数的该层的循环遍历,如此类推,即可。
(有说错的可以私信我,我好改正,谢谢!!)
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define N 100005
vector<int>edge[N];//edge[i]就是保存每一个点i的所有邻接点
//邻接点;就是顶点之间存在有边 ,就两个顶点互为邻接点
bool vis[N]={0};//用来标记该顶点i是否已经被标记过
int nn,mm;//nn顶点数,也就是 文章数,mm是边数,也就是被引用文献数
void insert(int xx,int yy){
edge[xx].push_back(yy);
//每加入一个值,都要把其重新排序,按从小到大,升序排列
for(int i=edge[xx].size()-1;i>0;i--){
if(edge[xx][i]<edge[xx][i-1]){
swap(edge[xx][i],edge[xx][i-1]);
}
}
//约等于sort()
}
void dfs(int u){
for(int v:edge[u]){
//遍历每个顶点的栈,然后从小到大遍历,遍历过的就不再遍历
if(vis[v]==false){
vis[v]=true;
cout<<v<<' ';
//递归
dfs(v);
}
}
}
void bfs(int su){
queue<int>q;
vis[su]=true;
cout<<su<<' ';
q.push(su);
//存入1,当队列为空时就结束循环。
while(q.empty()==false){
int z = q.front();
//由于单向队列的规则是先进先出,所以可以一个个从小到大依次遍历
q.pop();
for(int v:edge[z]){
if(vis[v]==false){
vis[v]=true;
cout<<v<<' ';
q.push(v);
}
}
}
}
// 0
//1 2
//3 4 5
//void bfs(int u)
int main(){
//这道题是有向图,较为简单。
cin>>nn>>mm;
int x,y;
for(int i=0;i<mm;i++){
cin>>x>>y;
insert(x,y);
}
vis[1]=true;
cout<<1<<' ';
dfs(1);
cout<<endl;
memset(vis,false,sizeof(vis));
//记录后需要重新清空用于标记的数组,然后再进行广搜。
bfs(1);
return 0;
}
这里是红糖,记录我的小白进化史。
希望能帮到你们,创作不易,如果觉得有帮助可以为我点个赞!!