发现环 (拓扑或dfs)

Posted zjl192628928

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了发现环 (拓扑或dfs)相关的知识,希望对你有一定的参考价值。

题目链接:http://lx.lanqiao.cn/problem.page?gpid=T453

问题描述

  小明的实验室有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
 
解题思路:第一种解法是用拓扑排序的方式,把度数为1的点去掉,然后剩下的度数为2的点就是答案了,第二种解法是用并查集找到环上相邻的两个点,然后用dfs一个为起点一个为终点,就可以搜索出答案。
代码:
第一种解法:
技术图片
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=100005;
int n,tot,head[maxn],in[maxn];
vector<int> ans;
struct node{
    int to,next;
}edge[2*maxn];
void add(int u,int v){
    edge[tot].to=v;
    edge[tot].next=head[u];
    head[u]=tot++;
}
void topsort(){
    queue<int> que;
    for(int i=1;i<=n;i++){
        if(in[i]==1)que.push(i);
    }
    while(que.size()){
        int now=que.front();
        que.pop();
        for(int i=head[now];i!=-1;i=edge[i].next){
            int v=edge[i].to;
            in[v]--;
            if(in[v]==1)que.push(v);
        }
    }
    for(int i=1;i<=n;i++){
        if(in[i]==2)ans.push_back(i);
    }
}
int main(){
    cin>>n;
    for(int i=0;i<=n;i++)head[i]=-1;
    for(int i=0;i<n;i++){
        int u,v;
        cin>>u>>v;
        add(u,v);
        add(v,u);
        in[u]++; in[v]++;
    }
    topsort();
    sort(ans.begin(),ans.end());
    for(int i=0;i<ans.size();i++)
    {
        printf("%d",ans[i]);
        if(i!=ans.size()-1)cout<<" ";
        else cout<<endl;
    }
    return 0;
}
View Code

第二种解法:

技术图片
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=100005;
int n,tot,st,ed,head[maxn],par[maxn],pre[maxn],vis[maxn];
vector<int> ans;
struct node{
    int to,next;
}edge[2*maxn];
void add(int u,int v){
    edge[tot].to=v;
    edge[tot].next=head[u];
    head[u]=tot++;
}
int find(int x){
    if(x==par[x])return x;
    else return par[x]=find(par[x]);
}
void unite(int x,int y){
    int fx=find(x),fy=find(y);
    par[fx]=fy;
}
void dfs(int x){
    vis[x]=1;
    for(int i=head[x];i!=-1;i=edge[i].next){
        int v=edge[i].to;
        if(!vis[v]){
            if(x==st&&v==ed)continue;
            vis[v]=1;
            pre[v]=x;
            if(v==ed)return;
            dfs(v);
        }
    }
}
int main(){
    cin>>n;
    for(int i=0;i<=n;i++){
        head[i]=-1;
        par[i]=i;
    }
    for(int i=0;i<n;i++){
        int u,v;
        cin>>u>>v;
        add(u,v);
        add(v,u);
        if(find(u)!=find(v))unite(u,v);
        else{
            st=u;
            ed=v;
        }
    }
    pre[st]=st;
    dfs(st);
    int tmp=ed;
    ans.push_back(ed);
    while(pre[tmp]!=tmp){
        tmp=pre[tmp];
        ans.push_back(tmp);
    }
    sort(ans.begin(),ans.end());
    for(int i=0;i<ans.size();i++)
    {
        printf("%d",ans[i]);
        if(i!=ans.size()-1)cout<<" ";
        else cout<<endl;
    }
    return 0;
}
View Code

 

以上是关于发现环 (拓扑或dfs)的主要内容,如果未能解决你的问题,请参考以下文章

CF1217D Coloring Edges 判断有无环的有向图

5.6 拓扑排序

hiho 第215周 Circle Detect(拓扑排序 | DFS)

4.29 模拟赛

HDU3342有向图判圈DFS&&拓扑排序法

CodeForces915 D. Almost Acyclic Graph 拓扑排序找环