zoukankan      html  css  js  c++  java
  • Warm up---hdu4612(缩点,树的直径)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4612

    给一个无向图, 加上一条边后,求桥最少有几个;

    那我们加的那条边的两个顶点u,v;一定是u,v之间含有桥的数量最多,然后uv之间的桥都没了,剩下的就是要求的结果;

    树的直径的定义刚好就是两个节点之间含有最多的边;

    下面是有关树的直径的知识;

    这个题目需要手动扩展,不然会爆栈,而且手动扩展的话要用C++提交。

    #pragma comment(linker, "/STACK:1024000000,1024000000")
    #include<stdio.h>
    #include<string.h>
    #include<queue>
    #include<algorithm>
    using namespace std;
    #define N 200005
    int Head1[N], Head2[N], cnt[3];
    int Stack[N], top, dfn[N], low[N], Time, n, m;
    int nBridge, Bridge[N];
    int dist[N], vis[N], Max, index, Is[N];
    struct Edge
    {
        int v, next;
    } e1[10*N], e2[10*N];
    void Init()
    {
        top = nBridge = Time = Max = index = 0;
        cnt[1] = cnt[0] = 0;
        memset(low, 0, sizeof(low));
        memset(dfn, 0, sizeof(dfn));
        memset(Bridge, 0, sizeof(Bridge));
        memset(dist, 0, sizeof(dist));
        memset(Stack, 0, sizeof(Stack));
        memset(Is, 0, sizeof(Is));
        memset(Head1, -1, sizeof(Head1));
        memset(Head2, -1, sizeof(Head2));
    }
    void Add(Edge e[],int Head[], int u, int v, int k)
    {
        e[cnt[k]].v = v;
        e[cnt[k]].next = Head[u];
        Head[u] = cnt[k]++;
    }
    void Tarjar(int u, int father)
    {
        low[u] = dfn[u] = ++Time;
        Stack[top++] = u;
        Is[u] = 1;
        int v, k=0;
        for(int i=Head1[u]; i!=-1; i=e1[i].next)
        {
            v = e1[i].v;
            if(v==father && !k)///避免重边;
            {
                k++;
                continue;
            }
            if(!dfn[v])
            {
                Tarjar(v, u);
                low[u] = min(low[u], low[v]);
            }
            else
                low[u] = min(low[u], dfn[v]);
        }
        if(low[u] == dfn[u])
        {
            nBridge++;///可以代表缩点后的节点个数;
            while(1)
            {
                v = Stack[--top];
                Is[v] = 0;
                Bridge[v] = nBridge;///缩点;
                if(u==v) break;
            }
        }
    }
    void bfs(int s)
    {
        queue<int>Q;
        int p, q;
        memset(vis, 0, sizeof(vis));
        vis[s] = 1;
        dist[s] = 0;
        Q.push(s);
        while(!Q.empty())
        {
            p = Q.front(); Q.pop();
            for(int i=Head2[p]; i!=-1; i=e2[i].next)
            {
                q = e2[i].v;
                if(!vis[q])
                {
                    vis[q] = 1;
                    dist[q] = dist[p] + 1;
                    Q.push(q);
                    if(Max<dist[q])
                    {
                        Max = dist[q];
                        index = q;
                    }
                }
            }
        }
    }
    int main()
    {
        int u, v;
        while(scanf("%d%d", &n, &m), m + n)///输入时由于m n弄反了,TLE的我想哭;
        {
            Init();
            for(int i=1; i<=m; i++)
            {
                scanf("%d%d", &u, &v);
                Add(e1, Head1, u, v, 0);
                Add(e1, Head1, v, u, 0);///原来的树;
            }
            Tarjar(1, 0);
            for(int i=1; i<=n; i++)
            {
                for(int j=Head1[i]; j!=-1; j=e1[j].next)
                {
                    int u = Bridge[i];
                    int v = Bridge[e1[j].v];
                    if(u != v )
                    {
                        Add(e2, Head2, u, v, 1);
                        Add(e2, Head2, v, u, 1);///缩点后的树;
                    }
                }
            }
            bfs(1);
            bfs(index);///求树的直径的过程;
            printf("%d
    ", nBridge-1-Max);///缩点后形成的树每条边都是桥;所以总桥的个数为节点数-1;
        }
        return 0;
    }
    View Code

     一年后又来写了一下,比不用扩栈也可以;

    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #include<vector>
    #include<queue>
    #include<string>
    #include<stack>
    #include<map>
    using namespace std;
    #define N 205010
    #define INF 0x3f3f3f3f
    #define met(a, b) memset(a, b, sizeof(a))
    
    vector<vector<int> >G;
    vector<vector<int> >G1;
    int low[N], dfn[N], Time;
    int Block[N], nblock;
    int IsStack[N], Sta[N], top;
    int n, m, nbridge;
    
    void Init()
    {
        met(low, 0);
        met(dfn, 0);
        met(Block, 0);
        met(IsStack, 0);
        met(Sta, 0);
        G.clear();
        G.resize(n+1);
        G1.clear();
        G1.resize(n+1);
        Time = nblock = top = nbridge = 0;
    }
    
    void Tarjan(int u, int fa)
    {
        low[u] = dfn[u] = ++Time;
        IsStack[u] = 1;
        Sta[top++] = u;
        int len = G[u].size(), v, k = 0;
        for(int i=0; i<len; i++)
        {
            v = G[u][i];
            if(v == fa && !k)
            {
                k++;
                continue;
            }
            if(!dfn[v])
            {
                Tarjan(v, u);
                low[u] = min(low[u], low[v]);
    
                if(low[v] > dfn[u])
                    nbridge ++;
            }
            else if(IsStack[v])
            {
                low[u] = min(low[u], dfn[v]);
            }
        }
        if(low[u] == dfn[u])
        {
            ++nblock;
            do
            {
                v = Sta[--top];
                IsStack[v] = 1;
                Block[v] = nblock;
            }while(u != v);
        }
    }
    
    int vis[N], Max, Index, dist[N];
    
    void bfs(int s)
    {
        met(vis, 0);
        met(dist, 0);
        vis[s] = 1;
        queue<int> Q;
        Q.push(s);
        while(Q.size())
        {
            int p = Q.front();Q.pop();
            int len = G1[p].size(), q;
            for(int i=0; i<len; i++)
            {
                q = G1[p][i];
                if(!vis[q] && dist[q] < dist[p]+1)
                {
                    dist[q] = dist[p]+1;
                    if(dist[q] > Max)
                    {
                        Max = dist[q];
                        Index = q;
                    }
                    vis[q] = 1;
                    Q.push(q);
                }
            }
        }
    }
    
    int main()
    {
        while(scanf("%d %d", &n, &m), m+n)
        {
            Init();
    
            int u, v;
            for(int i=1; i<=m; i++)
            {
                scanf("%d %d", &u, &v);
                G[u].push_back(v);
                G[v].push_back(u);
            }
            Tarjan(1, 0);
            for(int i=1; i<=n; i++)
            {
                int len = G[i].size(), v, u = Block[i];
                for(int j=0; j<len; j++)
                {
                    v = Block[G[i][j]];
                    if(u != v)
                    {
                        G1[u].push_back(v);
                        G1[v].push_back(u);
                    }
                }
            }
            Max = 0, Index = -1;
            bfs(1);
            bfs(Index);
            ///printf("%d %d
    ", nbridge, Max);
            printf("%d
    ", nbridge-Max);///或者nblock-1-Max;
        }
        return 0;
    }
    View Code
  • 相关阅读:
    HDU Intelligence System(tarjan+缩点)
    CF Easy Tape Programming(题意)
    poj 3694 Network(边双连通+LAC)
    20121116 CF DIV.2
    poj 2942 Knights of the Round Table(点双连通)
    解决Navihelper.dll(女生宿舍)病毒的方法一则
    在C++ Builder中调用FORTRAN生成的DLL
    过去的2004
    怎么取得DLL文件中的函数名列表?
    Gmail invitations
  • 原文地址:https://www.cnblogs.com/zhengguiping--9876/p/4729573.html
Copyright © 2011-2022 走看看