发现环

题目描述

题目来源:2017蓝桥杯国赛

小明的实验室有 N台电脑,编号 1⋯N。原本这 N 台电脑之间有 N-1条数据链接相连,恰好构成一个树形网络。在树形网络上,任意两台电脑之间有唯一的路径相连。

不过在最近一次维护网络时,管理员误操作使得某两台电脑之间增加了一条数据链接,于是网络中出现了环路。环路上的电脑由于两两之间不再是只有一条路径,使得这些电脑上的数据传输出现了 BUG。

为了恢复正常传输。小明需要找到所有在环路上的电脑,你能帮助他吗?

输入描述

输入范围:

第一行包含一个整数 N 。

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

其中, 1≤ N ≤10^5,1≤a,b≤N。

输入保证合法。

输出描述

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

输入输出样例

示例

输入

5
1 2
3 1
2 4
2 5
5 3

 

输出

1 2 3 5

 

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 256M

思路:

1. 本题的意思是从给出的图(图中有环)中找出在环中的结点,并输出;

2. 首先用邻接表来存储给定的图(本题中使用元素为set类型的vector来实现),不可以用二维数组或者邻接矩阵来存储边,会超时的;

3. 如果一个点在环中,那么这个点的度一定大于等于2,如果一个点的度为1,那么这个点肯定在环外;

4. 删除度为1的点和其所连接的边(因为不在环内的点不是我们想要的),重复这个动作直到没有度为1的点;那么剩余的点(度大于等于2)便是环内的点;

 

//2017g 发现环
#include <iostream>  vxgzh:xtsn
using namespace std;
#include <deque>
#include <vector>
#include <set>
#define N 100005
//邻接矩阵的应用(用别的会超时),
//从度为1的点开始,度为1不可能在环内;不断删除度为1的点和所连接的边;知道最后只存在度大于等于1的点,即环内的点

deque<int> dq;     //临时存储 度为1的点 
vector<int> ans;   //保存最终答案 

int main()
{
	int n,i,a,b;
	cin>>n;
	
	set <int> s;
	vector < set<int> > v(n+1);    //邻接表的数据结构,每个点的邻接点用集合表示 
	
	for(i=0;i<n;i++)   //输入 
	{
		cin>>a>>b;
		v[a].insert(b);v[b].insert(a);  //保存到邻接矩阵中去 
	}
	
	for(i=1;i<=n;i++)
	{
		if(v[i].size()==1)   //邻接矩阵中每个点连接的元素个数 即为度 
		{	
			int index=*v[i].begin();  //取出唯一的邻接点 
			v[i].erase(index);	v[index].erase(i);   //删掉边(i,index) ,也可理解为给i和index降度 
			if(v[index].size()==1)
			dq.push_back(index);
		}	
	}	
	while(!dq.empty())   //没有度为1的点时循环结束 
	{
		i=dq.front();dq.pop_front();
		int index=*v[i].begin();
		v[i].erase(index);  v[index].erase(i);
		if(v[index].size()==1)
		dq.push_back(index);
	}
	
	
	
	for(i=1;i<=n;i++)
		if(v[i].size()>=2)  //输出度数大于等于2的点 
			ans.push_back(i);
			
	for(i=0;i<ans.size()-1;i++)	 //输出结果	
		cout<<ans[i]<<" ";
	cout<<ans[i]<<endl;
	
	
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值