zoukankan      html  css  js  c++  java
  • 蓝桥杯 试题 历届试题 发现环 并查集+dfs

    问题描述
      小明的实验室有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

    解题思路:这一题可以用并查集的数据结构判断是否有环,用dfs递归找到环。

    并查集:并查集是用来管理元素分组情况的数据结构。注意并查集并不能高效的进行分割,可以高效地进行:
    • 查询a,b是否同组。
    • 合并a,b所在的组。

    具体实现用树形结构,如果a,b所在组相同,则a,b有相同的根结点。合并两组时即让一组的根向另一组相连。

    为了避免树形结构下发生退化的情况,在并查集中可以如下操作:

    • 对于每颗树,记录这颗树的高度.(rank)
    • 合并时,rank小的向rank大的连

    此外还可以路径压缩,即把每个结点都直接与其根结点相连,树的高度为2.在查询过程中查询过程中递归的所有节点都直接指向根结点。

    此时为方便起见,即使树的高度改变,我们也不修改rank的值(rank只是在合并时决定谁向谁连根)。

    具体见下实现代码。


    若(u,v)之间有边,则将u,v放入同一组。如果在放入u,v之前已经在同一组,即从u可以到v,那么加入边(u,v)后就形成了一个环。

    以u或v作为环的起点,用dfs方法遍历每个顶点相邻的顶点,看最后是否回到了起点,如果沿某一路径回到起点,则说明这些

    顶点在这个环内。


    实现代码:
    #include<cstdio>
    #include<algorithm>
    #include<vector>
    using namespace std;
    
    const int Max_N = 100000;
    
    //输入
    int n;
    int s;//环的起点 
    vector<int> G[Max_N+1];//
    vector<int> V;//记录环
    bool visited[Max_N+1];//结点是否访问过(避免重复访问) 
    
    int par[Max_N+1];//并查集
    int rank[Max_N+1];//并查集高度
    
    //初始化并查集
    void init(int n)
    {
        for(int i=1; i<=n; i++){//刚开始互相没有边相连 
            par[i] = i;
        }    
    } 
    
    //找下标x的根 
    int find(int x)
    {
        return x==par[x] ? x:par[x] = find(par[x]);//par[x] = find(par[x])即路径压缩 
    }
    
    //合并
    void unite(int x,int y)
    {
        x = find(x);    y=find(y);//先找到他们的根
        
        if( x==y ){
            return;//同根 直接返回 
        }    
        
        if( rank[x]<rank[y] ){
            par[x] = y;//将x所在的树合并在y下 
        }
        else
        {
            par[y] = x;
            if( rank[x]==rank[y] ){//如果高度相同 更新rank[x] 
                rank[x]++;
            }
        }
    } 
    
    //x,y是否在同一组 即是否同根 
    bool same(int x,int y)
    {
        return find(x)==find(y);    
    } 
    //dfs 
    bool dfs(int u)
    {
        if( visited[u] )//如果最后访问的结点回到起点,则在环内 
        {
            if( u==s )
            {
                return true;
            }
            return false;//否则不在环内 
        }
        
        visited[u] = true;//u已经访问过 
        
        for(int i=0; i<G[u].size(); i++)//遍历顶点 u 的相邻边 
        {
            int v = G[u][i];//下一个顶点
            if( dfs(v) )//在环内 
            {
                V.push_back(v);
                return true;    
            } 
        }
        return false;//遍历所有边都不在环内 
    } 
    
    void solve()
    {
        dfs(s);
        
        sort(V.begin(),V.end());
        
        vector<int>::iterator it;
        for( it=V.begin(); it!=V.end(); it++)
        {
            printf("%d ",*it);
        }
        printf("
    ");
    }
    
    int main()
    {
        scanf("%d",&n);
        init(n);
        while( n-- )
        {
            int u,v;
            scanf("%d%d",&u,&v);
            G[u].push_back(v);    G[v].push_back(u);
            if( same(u,v) ){//u,v已经有路径了 
                s = u;//起点下标 
            }
            unite(u,v);
        }
        
        solve();
        
        return 0;
    }

     实际上在dfs(v)判断为true后直接return的方法可能会出错(不过在样例中没有出现)。比如实际环为 1 2 3,但出现dfs(1)->dfs(2)->dfs(1)的情况,(如输入 3 ;1 2; 1 3; 2 3)

    此时保存的环为1 2。所以更好的方法是在dfs最后有true的情况就输出true,否则flase,并且保证不重复push_back节点。

  • 相关阅读:
    jmeter学习笔记(3)-jmeter结合fiddler
    jmeter学习笔记(2)—http信息头管理器+断言
    requests接口自动化9-共享session和传递cookie
    djangorestframework学习1-通过HyperlinkedModelSerializer,ModelViewSet,routers编写第一个接口
    requests接口自动化8-传递数据为xml形式的post请求:data
    requests接口自动化7-Multi/form-data文件上传形式的post请求:files
    requests接口自动化6-Body里json格式数据形式的post请求:json
    requests接口自动化5-表单参数形式的post请求:data
    requests接口自动化4-登录后才能访问的get请求,需共享cookie
    requests接口自动化3-url里带参数的get请求:params
  • 原文地址:https://www.cnblogs.com/w-like-code/p/12934398.html
Copyright © 2011-2022 走看看