zoukankan      html  css  js  c++  java
  • HDU 4612——Warm up——————【边双连通分量、树的直径】

                                  Warm up

    Time Limit:5000MS     Memory Limit:65535KB     64bit IO Format:%I64d & %I64u

    Description

      N planets are connected by M bidirectional channels that allow instant transportation. It's always possible to travel between any two planets through these channels. 
      If we can isolate some planets from others by breaking only one channel , the channel is called a bridge of the transportation system.
    People don't like to be isolated. So they ask what's the minimal number of bridges they can have if they decide to build a new channel. 
      Note that there could be more than one channel between two planets. 
     

    Input

      The input contains multiple cases. 
      Each case starts with two positive integers N and M , indicating the number of planets and the number of channels. 
      (2<=N<=200000, 1<=M<=1000000) 
      Next M lines each contains two positive integers A and B, indicating a channel between planet A and B in the system. Planets are numbered by 1..N. 
      A line with two integers '0' terminates the input.
     

    Output

      For each case, output the minimal number of bridges after building a new channel in a line.
     

    Sample Input

    4 4
    1 2
    1 3
    1 4
    2 3
    0 0
     

    Sample Output

    0
     
     
    题目大意:有n颗行星,有m条双向通道连接着m对行星。问你新建一条双向通道后,无向图中最少会剩下多少条桥。有重边。
     
    解题思路:无向图求边双连通分量,缩点,重新构图,形成树。求树的直径,然后用原图总的桥减去树的直径即为结果。求树的直径,我们用两次搜索,第一次从任意点出发,搜到的最远结点即为直径的一端,然后从这一端再次进行搜索,搜到直径的另一端。
     
    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #include<vector>
    #include<stack>
    using namespace std;
    const int maxn = 200100;
    struct Edge{
        int from,to,dist,next;
        Edge(){}
        Edge(int _to,int _next):to(_to),next(_next){}
    }edges[maxn*10];
    int head[maxn], tot;
    int dfs_clock, dfn[maxn], brinum;
    int Stack[maxn], instack[maxn], top, ebccno[maxn], ebcc_cnt;
    int deg[maxn];
    vector<int>G[maxn];
    void init(){
        tot = 0;
        brinum = dfs_clock = 0;
        top = 0;
        ebcc_cnt = 0;
        memset(deg,0,sizeof(deg));
        memset(head,-1,sizeof(head));
    }
    void AddEdge(int _u,int _v){
        edges[tot] = Edge(_v,head[_u]);
        head[_u] = tot++;
    }
    int dfs(int u,int fa){  
        int lowu = dfn[u] = ++dfs_clock;
        Stack[++top] = u;
       // instack[u] = 1;
        for(int i = head[u]; i != -1; i = edges[i].next){
            int v = edges[i].to;
            if(!dfn[v]){
                int lowv = dfs(v,i);
                lowu = min(lowu,lowv);
                if(lowv > dfn[u]){
                    brinum++;
                }
            }else if(dfn[v] < dfn[u] && (fa^1) != i){//这里用边的编号来标记是否是同一条边的回边
                lowu = min(lowu,dfn[v]);
            }
        }
        if(dfn[u] == lowu){     //找到一个边双连通分量
            ebcc_cnt++;
            for(;;){
                int v = Stack[top--];
             //   instack[v] = 0;
                ebccno[v] = ebcc_cnt;   //给每个点划分一个分量标号
                if(u == v){
                    break;
                }
            }
        }
      //  low[u] = lowu;
        return lowu;
    }
    void find_ebcc(int n){
        memset(dfn,0,sizeof(dfn));
        memset(instack,0,sizeof(instack));
        for(int i = 1; i <= n; i++){
            if(!dfn[i]){
                dfs(i,-1);
            }
        }
    }
    int pos, Maxd;
    void dfs1(int u,int dep,int fa){    //求树的直径
        if(dep > Maxd){
            Maxd = dep;
            pos = u;
        }
        for(int i = 0; i < G[u].size(); i++){
            int v = G[u][i];
            if(fa == v){ continue; }
            dfs1(v,dep+1,u);
        }
    }
    int main(){
        int n,m;
        while(scanf("%d%d",&n,&m)!=EOF&&(n+m)){
            init();
            for(int i = 0; i <= n; i++){
                G[i].clear();
            }
            int a,b;
            for(int i = 0; i < m; i++){
                scanf("%d%d",&a,&b);
                AddEdge(a,b);
                AddEdge(b,a);
            }
            find_ebcc(n);
            for(int i = 1; i <= n; i++){
                for(int j = head[i]; j != -1; j = edges[j].next){
                    int v = edges[j].to;
                    if(ebccno[i] != ebccno[v]){     //重新构图,形成树
                        G[ebccno[i]].push_back(ebccno[v]);
                    }
                }
            }
            pos = 1, Maxd = 0;
            dfs1(1,0,-1);
            int st = pos; Maxd = 0;
            dfs1(pos,0,-1);
            printf("%d
    ",brinum - Maxd);
        }
        return 0;
    }
    

      

     
     
  • 相关阅读:
    js快速排序
    蛇形数组
    大臣的旅费
    1724ROADS
    2738:实数加法
    完整版高精度计算(整理后的)
    2737:大整数除法
    2980:大整数乘法
    2736大整数减法,3180 整数减法
    2981:大整数加法
  • 原文地址:https://www.cnblogs.com/chengsheng/p/4943573.html
Copyright © 2011-2022 走看看