POJ 3352 Road Construction(添最少边构造边双连通图的结论)

题意:已知无向图,问添加最少的边使之成为边双连通图

思路:显然先缩点成一棵树,添加最少边使一棵树的边双连通


此处有结论:对于一棵树添加(1+leaf)>>1 条无向边就能构造成一个双连通图,构造方法显然(脑补一下


    //216K	63MS	C++	1754B
    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    using namespace std;

    const int N = 1010;
    struct node
    {
        int v,next;
    }es[N*N];
    int head[N];
    int n,m;
    int low[N],dfn[N],index;
    int indeg[N];

    void ini()
    {
        memset(head,-1,sizeof(head));
        memset(dfn,0,sizeof(dfn));
        index=0;
        memset(indeg,0,sizeof(indeg));
    }

    void tarjan(int u,int pa)
    {
        dfn[u]=low[u]=++index;
        for(int i=head[u];~i;i=es[i].next)
        {
            int v=es[i].v;
            if(dfn[v]==0)
            {
                tarjan(v,u);
                low[u]=min(low[u],low[v]);
            }
            if(v!=pa) low[u]=min(low[u],low[v]);
        }
    }
    int main()
    {


        while(~scanf("%d%d",&n,&m))
        {
            ini();
            for(int i=1;i<=m;i++)
            {
                int u,v;
                scanf("%d%d",&u,&v);
                es[i].v=v;
                es[i].next=head[u];
                head[u]=i;
                es[i+m].v=u;
                es[i+m].next=head[v];
                head[v]=i+m;
            }

            for(int i=1;i<=n;i++) if(dfn[i]==0) tarjan(i,-1);

            for(int u=1;u<=n;u++)
            {
                for(int i=head[u];~i;i=es[i].next)
                {
                    int v= es[i].v;
                    if(low[v]==low[u]) continue;
                    indeg[low[u]]++;
                }
            }
            int leaf=0;
            for(int i=1;i<=n;i++)
                if(indeg[i]==1) leaf++;
            printf("%d\n",(leaf+1)/2);

        }

        return 0;
    }

上面这个代码是自己改编的一个tarjan,只有在这题中能用,还没证明出明确的错误,下面的是正解:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cstring>
using namespace std;

int n,m;
const int N = 1000+100;
const int M = 2*N;
int head[N],cnt;
struct Edge
{
    int v,nxt;
}es[M];

inline void add_edge(int u,int v)
{
    es[cnt].v=v;
    es[cnt].nxt=head[u];
    head[u]=cnt++;
    es[cnt].v=u;
    es[cnt].nxt=head[v];
    head[v]=cnt++;
}
typedef pair<int,int>pii;
pii bridge[M];
int dfn[N],sta[N],top,scc,index,col[N],low[N],cbr;
void tarjan(int u,int pa)
{
    dfn[u]=low[u]=++index;
    sta[++top]=u;
    for(int i=head[u];~i;i=es[i].nxt)
    {
        int v=es[i].v;
        if(v==pa) continue;
        if(dfn[v]==0)
        {
            tarjan(v,u);
            low[u]=min(low[u],low[v]);
            if(low[v]>dfn[u])
            {
                scc++;
                int vv;
                do
                {
                    vv=sta[top--];
                    col[vv]=scc;
                }while(vv!=v);
                bridge[++cbr]=pii(u,v);
            }
        }
        else low[u]=min(low[u],dfn[v]);
    }
}
int in[N];
void ini()
{
    memset(dfn,0,sizeof(dfn));
    memset(col,0,sizeof(col));
    memset(in,0,sizeof(in));
    memset(head,-1,sizeof(head));
    top=scc=cbr=index=cnt=0;
}
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        ini();
        for(int i=1;i<=m;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            add_edge(u,v);
        }
        for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i,-1);
        if(top) scc++;
        while(top)
        {
            col[sta[top--]]=scc;
        }
        for(int i=1;i<=cbr;i++)
        {
            int u=bridge[i].first,v=bridge[i].second;
            in[col[u]]++;
            in[col[v]]++;
        }
        int leaf=0;
        for(int i=1;i<=scc;i++) if(in[i]==1)leaf++;
        printf("%d\n",(leaf+1)>>1);
    }
    return 0;

}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值