zoukankan      html  css  js  c++  java
  • poj 3177Redundant Paths(边双连通分支)

    题目链接:http://poj.org/problem?id=3177

    题意:给出一个n个点,m条边的连通图,问至少加几条边使两两点可以至少两条路到达。

    思路:题目就是要将一个有桥的连通图变成双连通图。   

    把双连通子图缩点,形成一颗树。假设树的叶子节点有leaf个,至少要加的边数就是(leaf+1)/2。

    为什么是(leaf+1)/2?只要两两叶子成对相连即可。

    代码:

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #define inf 0x3f3f3f3f
    using namespace std;
    typedef long long ll;
    const int maxn=5500;
    const int maxm=20050;
    struct node{
        int u,v,w,nxt,cut;
    }e[maxm];
    int h[maxn],dfn[maxn],low[maxn],st[maxn],vis[maxn];
    int du[maxn],belong[maxn],num,cnt,tot,top,ans,n,m; 
    
    void add(int u,int v)
    {
        e[cnt].u=u;
        e[cnt].v=v;
        e[cnt].cut=0;
        e[cnt].nxt=h[u];
        h[u]=cnt++;
    }
    
    void tarjan(int u,int pre)
    {
        dfn[u]=low[u]=++tot;
        vis[u]=1; 
        st[++top]=u;
        int pre_cnt=0; 
        for(int i=h[u];i!=-1;i=e[i].nxt)
        {
            int v=e[i].v;
            if(v==pre&&pre_cnt==0)    
            {
                pre_cnt++;
                continue;
            }
            if(!dfn[v]) 
            {
                tarjan(v,u); 
                low[u]=min(low[u],low[v]);  
                if(low[v]>dfn[u])//
                {
                    e[i].cut=1;
                    e[i^1].cut=1;
                }  
            }
            else if(vis[v]) 
                low[u]=min(low[u],dfn[v]);
        }
        
        if(dfn[u]==low[u]) 
        {
            int t;
            num++; 
            do{
                t=st[top--]; 
                vis[t]=0; 
                belong[t]=num; 
            }while(t!=u);
        }
    }
    int main()
    {
        int u,v;
        cnt=top=tot=ans=0;
        memset(h,-1,sizeof(h));
        memset(du,0,sizeof(du));
        memset(dfn,0,sizeof(dfn));
        memset(vis,0,sizeof(vis));
        scanf("%d%d",&n,&m);
        for(int i=0;i<m;i++)
        {
            scanf("%d%d",&u,&v);
            add(u,v);
            add(v,u);
        }
        tarjan(1,0); 
        for(int i=1;i<=n;i++)
        {
            for(int j=h[i];j!=-1;j=e[j].nxt)
            {
                if(e[j].cut)
                    du[belong[i]]++;
            }
        }
        for(int i=1;i<=num;i++)
        {
            //cout<<i<<' '<<du[i]<<endl;
            if(du[i]==1)
                ans++;
        }    
        printf("%d
    ",(ans+1)/2);
        return 0;
    }
  • 相关阅读:
    mixin混合
    python类内部调用自己的成员函数必须加self
    合并/取消合并单元格
    pandas 显示所有的行和列
    pandas 利用openpyxl设置表格样式
    Nowcoder9983G.糖果(并查集)
    Nowcoder9983F.匹配串(思维)
    Nowcoder9983E.买礼物(链表+线段树)
    Nowcoder9983C.重力追击(暴力+少用sqrt)
    Nowcoder9983B.内卷(双指针)
  • 原文地址:https://www.cnblogs.com/xiongtao/p/11250379.html
Copyright © 2011-2022 走看看