P5318 【深基18.例3】查找文献题解

文章描述了一种问题情境:在一篇包含参考文献的博客文章网络中,小K需要找到一个字典序最小的遍历顺序,首先完成DFS和BFS算法,并且考虑到节点数量较多,使用邻接表和排序。给出的代码示例展示了如何实现这两个搜索算法以遍历文章网络。
摘要由CSDN通过智能技术生成

题目

小K喜欢翻看洛谷博客获取知识。每篇文章可能会有若干个(也有可能没有)参考文献的链接指向别的博客文章。小K求知欲旺盛,如果他看了某篇文章,那么他一定会去看这篇文章的参考文献(如果他之前已经看过这篇参考文献的话就不用再看它了)。

假设洛谷博客里面一共有n(n≤10^{5})篇文章(编号为1到n)以及m(m≤10^{6}) 条参考文献引用关系。目前小K已经打开了编号为1的一篇文章,请帮助小K设计一种方法,使小K可以不重复、不遗漏的看完所有他能看到的文章。

这边是已经整理好的参考文献关系图,其中,文献X → Y表示文章X有参考文献Y。不保证编号为1的文章没有被其他文章引用。

请对这个图分别进行DFS和BFS,并输出遍历结果。如果有很多篇文章可以参阅,请先看编号较小的那篇(因此你可能需要先排序)。

输入输出格式

输入格式

共m+1行,第1行为2个数,n和m,分别表示一共有n(n≤10^{5}) 篇文章(编号为1到n)以及m(m≤10^{6}) 条参考文献引用关系。

接下来m行,每行有两个整数X,Y表示文章X有参考文献Y。

输出格式

共2行。 第一行为DFS遍历结果,第二行为BFS遍历结果。

输入输出样例

输入样例

8 9
1 2
1 3
1 4
2 5
2 6
3 7
4 7
4 8
7 8

输出样例

1 2 5 6 3 7 8 4 
1 2 3 4 5 6 7 8 

解析

题目大意可以概括一下:有一张有向图,求其进行深度优先搜索(DFS)和广度优先搜索(BFS)的两个字典序最小的遍历序列。

DFS,用通俗的话来说,就是你从图的一个结点出发,选择了下一个你需要遍历的结点,然后你再以你所选择的点作为新的起点,继续向下选择,直到你选择的结点没有了下一个结点,或者它所有的子节点都被访问过。

那你就要按照你选择的路径,依次跳回,直到你跳回的节点有了字节点,再进行遍历,以此类推。

BFS,用通俗的话来说,就是你从图中的一个节点出发,其有几个子节点,你会先将这所有的子节点遍历,再挑其中的一个子节点,遍历它的所有子节点,再换到另外一个结点遍历其所有的子节点。这样一层层遍历,以此类推。

对于DFS,由于它需要往回跳,所以就需要用递归算法;

对于BFS,由于它需要一层层遍历,所以需要用一个数据结构来存储每一层的节点,而根据我所描述的,选用队列(queue)是最为合适的。

对了,这道题节点数≤10^{5},使用邻接矩阵会MLE,那么就只能考虑采用邻接表。

又由于本题需要求字典序最小的序列,那么就要将邻接表存储的结点按从小到大进行排序。

总体就是这样的,记得两次遍历中间要清空你遍历时所需要的标记数组。

#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=100010;
vector<int>G[maxn];
queue<int>q;
int n,m;
bool vis[maxn];
void dfs(int x,int cur){
	vis[x]=true;
	cout<<x<<" ";
	if(cur==n){
		return;
	}
	for(int i=0;i<G[x].size();i++){
		if(!vis[G[x][i]]){
			dfs(G[x][i],cur+1);
		}
	}
}
void bfs(int x){
	memset(vis,false,sizeof(vis));
	vis[x]=true;
	q.push(x);
	while(!q.empty()){
		int v=q.front();
		q.pop();
		cout<<v<<" ";
		for(int i=0;i<G[v].size();i++){
			if(!vis[G[v][i]]){
				vis[G[v][i]]=true;
				q.push(G[v][i]);
			}
		}
	}
}
int main(){
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		int u,v;
		cin>>u>>v;
		G[u].push_back(v);
	}
	for(int i=1;i<=n;i++){
		sort(G[i].begin(),G[i].end());
	}
	dfs(1,0);
	cout<<endl;
	bfs(1);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

互联网的猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值