P8655 [蓝桥杯 2017 国 B] 发现环 题解

题目回顾

P8655 [蓝桥杯 2017 国 B] 发现环

题目描述

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

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

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

输入格式

第一行包含一个整数 \(N\)

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

输入保证合法。

输出格式

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

样例 #1

样例输入 #1

5
1 2
3 1
2 4
2 5
5 3

样例输出 #1

1 2 3 5

提示

对于 \(30\%\) 的数据,\(1 \le N \le 1000\)

对于 \(100\%\) 的数据,\(1 \le N \le 10^5\)\(1 \le a,b \le N\)

时限 1 秒, 256M。蓝桥杯 2017 年第八届国赛

思路:

对于这道题我的思路类似于拓补排序

首先可以将无向图转化为有向图,即将对于每条无向边变换为双向建边,就好处理了。

在这种情况下,很显然当一个点的入度大于或等于 \(2\) 时,即有不止一条边连向这个点时,该点就在环上。

我们可以建一个布尔类型 \(vis\) 数组来标记这个点的入度是否等于 \(1\),那么这个点就不在环上,那么没有被标记的点就是我们要求的答案了。

Code

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+1; 
int n;
int in[N];
vector<int>e[N];
bool vis[N];//标记入度是否为1,即该点是否在环上
void topo()//拓补排序
{
	queue<int>q;
	for(int i=1;i<=n;i++)
		if(in[i]==1)//标记入度为1的点
		{
			q.push(i);
			vis[i]=true;
		}
	while(!q.empty())
	{
		int u=q.front();
		q.pop();
		for(int i=0;i<e[u].size();i++)
		{
			int v=e[u][i];
			in[v]--;
			if(in[v]==1)//标记入度为1的点
			{
				q.push(v);
				vis[v]=true;
			}
		}
	}
}
void print()//输出未标记的点
{
	for(int i=1;i<=n;i++)
		if(!vis[i])cout<<i<<' ';
}
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		int u,v;
		cin>>u>>v;
		e[u].push_back(v);
		e[v].push_back(u);//双向建边
		in[u]++;
		in[v]++;//两点的入度都增加
	}
	topo();
	print();
	return 0;
}
posted @ 2023-05-06 21:59  FHenryh  阅读(82)  评论(0)    收藏  举报