洛谷P5318查找文献题解||有向图算法基础题

收到学弟的催更,小透明佛系博主来更新一下。

做这道题之前呢,我们需要先了解图的存储(可以用三个数组,一个变量去存储,也可以用队列,栈去存储,看个人怎么用),深度优先搜索(就是一列一列地搜索,类似于递归)和宽度优先搜索(就是一层层地遍历)。

这里应该放一篇我自己写到深搜和广搜的解释的推文,但是我没有,后期有空补一篇

首先,这道题的大概思路就是先存储数到图中,然后深搜,再然后广搜一次。

听起来思路很简单理解。

下面可是正式操作:

一、存数

我们可以开一个栈数组来存储数,然后开一个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;
}

这里是红糖,记录我的小白进化史。

希望能帮到你们,创作不易,如果觉得有帮助可以为我点个赞!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值