zoukankan      html  css  js  c++  java
  • POJ

    题意:在一张图中最少可以添加几条边,使其中任意两点间都有两条不重复的路径(路径中任意一条边都不同)。

    分析:问题就是最少添加几条边,使其成为边双连通图。可以先将图中所有边双连通分量缩点,之后得到的就是一棵树。

    那么问题又转化成为:在这棵树上添加几条边使其成为一个双连通分量。答案是缩点之后(leaf+1)/2,其中leaf是树的叶节点个数。

    具体方法为,首先把两个最近公共祖先最远的两个叶节点之间连接一条边,这样可以把这两个点到祖先的路径上所有点收缩到一起,因为一个形成的环一定是双连通的。然后这样不断一对一地找完,次数正好是(leaf+1)/2次。
    #include<iostream>
    #include<stdio.h>
    #include<stack>
    #include<algorithm>
    #include<cstring>
    #include<vector>
    using namespace std;
    const int maxn =5e4+5;
    struct Edge{
        int to,next;
    }edges[maxn<<2];
    bool instack[maxn];
    int bccno[maxn],head[maxn],dfn[maxn],low[maxn],degree[maxn],clk,top,scc;
    stack<int> S;
    
    void init()
    {
        clk = top = scc =0;
        memset(head,-1,sizeof(head));
        memset(dfn,0,sizeof(dfn));
        memset(bccno,0,sizeof(bccno));
        memset(instack,0,sizeof(instack));
        memset(degree,0,sizeof(degree));
    }
    
    void AddEdge(int u,int v)
    {
        edges[top].to = v;
        edges[top].next =head[u];
        head[u] = top++;
    }
    
    void Tarjan(int u,int id)
    {
        int v;
        low[u]=dfn[u]=++clk;
        S.push(u);
        instack[u]=true;
        for(int i=head[u];i!=-1;i=edges[i].next){
            v = edges[i].to;
            if(i==(id^1))   continue;
            if(!dfn[v]){
                Tarjan(v,i);
                low[u]=min(low[u],low[v]);
            }
            else if(instack[v])
                low[u]= min(low[u],dfn[v]);
        }
        if(dfn[u]==low[u]){     //找到一个双连通分量
            scc++;                  //从1开始
            int x;
            while(true){
                x =S.top();S.pop();
                bccno[x]=scc;               //确定分量编号
                instack[x]=false;
                if(x==u)    break;      //找到了自己就要停止标号
            }
        }
    }
    
    int main()
    {
        int N,M,v,u,tmp;
        while(~scanf("%d%d",&N,&M)){
            init();
            for(int i=0;i<M;++i){
                scanf("%d%d",&u,&v);
                AddEdge(u,v);
                AddEdge(v,u);
            }
            Tarjan(1,-1);
            for(int i=1;i<=N;++i){
                for(int j =head[i];j!=-1;j=edges[j].next){
                    v = edges[j].to;
                    if(bccno[i]!=bccno[v]){     //根据分量编号缩点,计算度
                        degree[bccno[i]]++;     
                    }
                }
            }
            int res=0;
            for(int i=1;i<=scc;++i){
                if(degree[i]==1)
                    res++;
            }
            printf("%d
    ",(res+1)/2);
        }
        return 0;
    }
     
    为了更好的明天
  • 相关阅读:
    Invoice Helper
    Product Helper
    Order Helper
    Case Helper
    Quote Helper
    C# 工厂模式示例
    若今生长剑浣花,生死无涯
    古代美到窒息的谎言
    C#解决微信支付Exception has been thrown by the target of an invocation(调用的目标发生了异常)的问题
    文能提笔控萝莉,转载自网上
  • 原文地址:https://www.cnblogs.com/xiuwenli/p/9400060.html
Copyright © 2011-2022 走看看