本文主要是介绍蓝桥杯 2017 决赛 发现环 (求环内的点),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
历届试题 发现环
时间限制:1.0s 内存限制:256.0MB
问题描述
小明的实验室有N台电脑,编号1~N。原本这N台电脑之间有N-1条数据链接相连,恰好构成一个树形网络。在树形网络上,任意两台电脑之间有唯一的路径相连。
不过在最近一次维护网络时,管理员误操作使得某两台电脑之间增加了一条数据链接,于是网络中出现了环路。环路上的电脑由于两两之间不再是只有一条路径,使得这些电脑上的数据传输出现了BUG。
为了恢复正常传输。小明需要找到所有在环路上的电脑,你能帮助他吗?
不过在最近一次维护网络时,管理员误操作使得某两台电脑之间增加了一条数据链接,于是网络中出现了环路。环路上的电脑由于两两之间不再是只有一条路径,使得这些电脑上的数据传输出现了BUG。
为了恢复正常传输。小明需要找到所有在环路上的电脑,你能帮助他吗?
输入格式
第一行包含一个整数N。
以下N行每行两个整数a和b,表示a和b之间有一条数据链接相连。
对于30%的数据,1 <= N <= 1000
对于100%的数据, 1 <= N <= 100000, 1 <= a, b <= 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 1
2 4
2 5
5 3
样例输出
1 2 3 5
方法一:dfs
#include<stdio.h>
#include<string.h>
#include<vector>
#include<stack>
using namespace std;
const int N = 100000+5;
int n;
bool vis[N];
vector<int> adj[N];
bool in_stack[N];
bool flag[N];
stack<int> s;void dfs(int cur,int fa){vis[cur] = true;s.push(cur);in_stack[cur] = true;for(int i = 0; i < adj[cur].size(); ++i){int v = adj[cur][i];if(!vis[v]){dfs(v,cur);}else if(in_stack[v] && fa != v){//不能是父节点int u;do{u = s.top();flag[u] = true;s.pop();}while(u != v);//return; // 不知道为啥 不能 直接return; break;}} if(!s.empty()) //这里如果不判断 直接出栈 会RE 从 100 -> 0 悲剧 s.pop();in_stack[cur] = false; //出栈了必须标记 }int main(){scanf("%d",&n);int a,b;for(int i = 0; i < n; ++i){scanf("%d%d",&a,&b);adj[a].push_back(b);adj[b].push_back(a);}dfs(1,1); //图一定连通 所以 从一个点搜索就OK了
// for(int i = 1; i <= n; ++i){
// if(!vis[i]){
// dfs(i,i);
// }
// }for(int i = 1; i <= n; ++i){if(flag[i]){printf("%d ",i);}}return 0;}
方法二:tarjan变形(原算法主要针对有向图) 这里根据求割点的方法变形
关键在于:对顶点u 其子树经过 非父子边所能回到的最早的时间戳
#include<stdio.h>
#include<string.h>
#include<vector>
#include<stack>
#include<algorithm>
using namespace std;
const int N = 100000+5;
int n;
bool vis[N];
vector<int> adj[N];
bool in_stack[N];
bool flag[N];
stack<int> s;
int index;
int low[N];
int dfn[N];
int color;
vector<int> cop[N];//记录每个连通分量 其实只有一个 void dfs(int cur,int fa){dfn[cur] = low[cur] = ++index;vis[cur] = true;s.push(cur);in_stack[cur] = true;for(int i = 0; i < adj[cur].size(); ++i){int v = adj[cur][i];if(!vis[v]){dfs(v,cur);low[cur] = min(low[cur],low[v]);}else if(in_stack[v] && v != fa){ //这是关键 不能是父节点 类似于判断割点 low[cur] = min(low[cur],dfn[v]);}}in_stack[cur] = false;if(low[cur] == dfn[cur]){ //说明是个连通分量 int u;++color;do{u = s.top();cop[color].push_back(u);s.pop();}while(u != cur);} }int main(){scanf("%d",&n);int a,b;for(int i = 0; i < n; ++i){scanf("%d%d",&a,&b);adj[a].push_back(b);adj[b].push_back(a);}dfs(1,1); //图一定连通 所以 从一个点搜索就OK了 for(int i = 0; i < N; ++i){if(cop[i].size() > 1){for(int j = 0; j < cop[i].size(); ++j){sort(cop[i].begin(),cop[i].end());//排序 printf("%d ",cop[i][j]);}}}return 0;}
这篇关于蓝桥杯 2017 决赛 发现环 (求环内的点)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!