蓝桥杯 历届试题 发现环 搜索简单环

问题描述

  小明的实验室有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

题目思路

首先我写的代码应该是有问题的,可能连数据都没输入完答案就出来了,但确实是AC了(大概数据里都是最后一条边输入才会生成环),代码先放这里,下次优化

基本思路:先并查集判断当一条边的两个顶点的祖先一样,说明这两个点是环的一部分,从一个点出发dfs到另一个顶点即可

还有一个思路是在网上看的:拓扑排序每次删掉度为1的点,一直删一直删,剩下的就是环了

AC代码

#include<iostream>
#include<stack>
#include<vector>
#include<algorithm>
#include<cstdio>
using namespace std;
const int maxn = 100010;
int per[maxn];
int n;
vector<int> e[maxn];
stack<int>res;
int vis[maxn];
int a[maxn];
int find(int x){
    if (x == per[x])
        return x;
    return per[x] = find(per[x]);
}
void join(int x, int y){
    int fx = find(x), fy = find(y);
    if (fx != fy)
        per[fx] = fy;
}
void print(){
    int t = 0;
    while (!res.empty()){
        a[t++] = res.top();
        res.pop();
    }
    sort(a,a+t);
    for (int i = 0; i < t-1; i++){
        cout << a[i] << ' ';
    }
    cout << a[t - 1] << endl;
}
void dfs(int start,int end){
    res.push(start);
    vis[start] = 1;
    if (start == end){
        print();
        exit(0);
    }
    for (int i = 0; i < e[start].size(); i++){
        if (e[e[start][i]].size() >= 2 && vis[e[start][i]] == 0)
            dfs(e[start][i], end);
    }
    res.pop();
    vis[start] = 0;
}
int main()
{
    int a, b;
    cin >> n;
    for (int i = 0; i <= n; i++){ per[i] = i; vis[i] = 0; }
    for (int i = 1; i <= n; i++){
        scanf("%d%d",&a,&b);
        e[a].push_back(b);
        e[b].push_back(a);
        int fa = find(a), fb = find(b);
        if (fa != fb)
            per[fa] = fb;
        else dfs(a,b);
    }
    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/looeyWei/p/10462634.html