蓝桥杯PREV-49 发现环 【伪拓扑排序】

时间限制:1.0s   内存限制:256.0MB

问题描述

  小明的实验室有N台电脑,编号1~N。原本这N台电脑之间有N-1条数据链接相连,恰好构成一个树形网络。在树形网络上,任意两台电脑之间有唯一的路径相连。
  不过在最近一次维护网络时,管理员误操作使得某两台电脑之间增加了一条数据链接,于是网络中出现了环路。环路上的电脑由于两两之间不再是只有一条路径,使得这些电脑上的数据传输出现了BUG。
  为了恢复正常传输。小明需要找到所有在环路上的电脑,你能帮助他吗?

输入格式

  第一行包含一个整数N。
  以下N行每行两个整数a和b,表示a和b之间有一条数据链接相连。


  对于30%的数据,1 <= N <= 1000
  对于100%的数据, 1 <= N <= 100000, 1 <= a, b <= N
  输入保证合法。

输出格式

  按从小到大的顺序输出在环路上的电脑的编号,中间由一个空格分隔。

样例输入

5
1 2
3 1
2 4
2 5
5 3

样例输出

1 2 3 5

解题思路 

   这题有很多种做法,可以并查集+搜索(有空写出来贴上),也可以用类似的方法拓扑排序,实现起来最简单的是拓扑排序。

思路:

条件:如果无向图中的一个点在环中,那么他的度至少为2.

方法:(由有向图的拓扑排序推广到无向图)

① 记录所有度为1的点,这些点必然不在环中,则与他们相关联的边也不是环上的边,因此删除所有与这些点相关联的边,并删除这些点。

② 重复①操作。

③ 如果①②结束后,仍有点,说明这些点在环中。输出。

AC代码

#include <cstdio>
#include <set>
#include <queue>
using namespace std;
const int maxn = 1e5+5;
set<int > s[maxn];
int main()
{
	int n;
	scanf("%d",&n);
	int u,v;
	for(int i=1;i<=n;i++) {
		scanf("%d %d",&u,&v);
		s[u].insert(v);
		s[v].insert(u);
	}	
	
	queue<int > q;
	int cnt=0;	//记录"拓扑排序"删掉了多少点 
	for(int i=1;i<=n;i++)
		if(s[i].size() == 1) {
			cnt++;
			q.push(i);			//出边为1的点
		}
		
	while(!q.empty()) {
		int j = q.front();
		int to = *s[j].begin();
		s[to].erase(j);
		if(s[to].size() == 1) {
			cnt++;
			q.push(to);	
		
		}
		s[j].clear();
		q.pop();
	} 
	cnt = n-cnt;	//回路中的点数
	for(int i=1;i<=n;i++) { 
		if(s[i].size()) {	//还有边(其实是至少两条)与其关联,说明这个点在环中 
			if(cnt != 1)
				printf("%d ",i);
			else
				printf("%d\n",i);
		}
	} 
} 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值