藍橋 - 發現環 dfs(+並查集)/拓撲判環 自己方法很迷 很迷。。。

題目放在文章最後了。
大意是一棵樹 加了一條邊
問你迴路上所有點是什麼
學長講題是拓撲判環
自己dfs瞎搞 搞出來的
兩種 一種用並查集 一種不用
。。。。。。。。。。。。。。。。
感覺自己方法特別迷 我都不知道怎麼搞出來的- -。。。。。
剛剛發現:題解中的答案是用並查集但是這個並查集是不加上成環的邊
我的思路是 加着成環的邊。
而我的不加並查集 純搜索也搞出來了 但是會有重複情況出現(重複一個起點
所以要unique去重一下
下面是各種代碼(拓撲直接引鏈接
1、拓撲判環
https://msd.misuland.com/pd/3070888491219948468
2、題解並查集+dfs 不加成環邊
https://blog.csdn.net/tianwei0822/article/details/80422483
3、自己的並查集+dfs 加上成環邊 (就很迷- -

//突然發現dfs裏的後兩個參數然並卵
const int maxn=1e5+10;
int n,cnt,k;//迴路上兩點
struct Side{
    int v,next;
}side[maxn<<1];
int head[maxn];
int ans[maxn];
bool con[maxn];
int pre[maxn];
int find(int x){
    if(x==pre[x]) return x;
    return pre[x]=find(pre[x]);
}
void join(int a,int b){
    int fa=find(a),fb=find(b);
    if(fa<fb) pre[fb]=fa;
    else if(fb<fa) pre[fa]=fb;
    return;
}
void add(int u,int v){
    side[cnt].v=v;
    side[cnt].next=head[u];
    head[u]=cnt++;
}
bool dfs(int u,int pre,int s,int t){
    con[u]=true;
    for(int i=head[u];i!=-1;i=side[i].next){
        int v=side[i].v;
        if(con[v]){//若下一個來過
            if(v==pre) continue;//若是父親 不行
            else{
                ans[++k]=v;
                return true;
            }
        }
        if(dfs(v,u,s,t)){//若搜到了迴路
            ans[++k]=v;
            return true;
        }
    }
    return false;
}
void init(){
    cnt=0,k=0;
    rep(i,1,n){
        head[i]=-1;
        con[i]=0;
        pre[i]=i;
    }
}
int main() {
    sd(n);
    init();
    int u,v,u1,v1;
    rep(i,1,n){
        sdd(u,v);
        add(u,v);add(v,u);
        if(find(u)==find(v)){
            u1=u;v1=v;//找到迴路上兩點
        }
        join(u,v);
    }
    dfs(u1,0,u1,v1);
    sort(ans+1,ans+k+1);
    for(int i=1;i<=k;i++) {
        printf("%d",ans[i]);
        putchar(i==k?'\n':' ');
    }
    //system("pause");
	return 0;
}

4、自己的dfs不加並查集(自己也不知道怎麼過的 要去重一下

using namespace std;
const int maxn=1e5+10;
int n,cnt,k;//迴路上兩點
struct Side{
    int v,next;
}side[maxn<<1];
int head[maxn],ans[maxn];
bool con[maxn];
void add(int u,int v){
    side[cnt].v=v;
    side[cnt].next=head[u];
    head[u]=cnt++;
}
bool dfs(int u,int pre){
    con[u]=true;
    for(int i=head[u];i!=-1;i=side[i].next){
        int v=side[i].v;
        if(con[v]){//若下一個來過
            if(v==pre) continue;//若是父親 不行
            else{
                ans[++k]=v;
                return true;
            }
        }
        if(dfs(v,u)){//若搜到了迴路
            ans[++k]=v;
            return true;
        }
    }
    return false;
}
void init(){
    cnt=0,k=0;
    rep(i,1,n){
        head[i]=-1;
        con[i]=0;
    }
}
int main() {
    sd(n);
    init();
    int u,v;
    rep(i,1,n){
        sdd(u,v);
        add(u,v);add(v,u);
    }
    dfs(1,0);
    sort(ans+1,ans+k+1);
    int size=unique(ans+1,ans+k+1)-ans-1;
    for(int i=1;i<=size;i++) {
        printf("%d",ans[i]);
        putchar(i==size?'\n':' ');
    }//system("pause");
	return 0;
}

題目描述
小明的實驗室有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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章