POJ3352 Road Construction【边双联通分量】【Tarjan】

题目链接:

http://poj.org/problem?id=3352


题目大意:

一个热带天堂岛上有N个旅游景点,任意2个旅游景点之间都有路径(并不一定直接相连)。为了使游客

往返更便捷,该旅游公司要求增加一些道路。在施工的时候,每次只能选择一条道路施工,在施工完

毕之前,除了该道路意外,其他道路依旧能够通行。因为施工道路禁止通行,这就导致了在施工期间

游客可能无法到达一些经典。

该公司为了保证在施工期间所有的旅游景点都能够向游客开放,该公司决定搭建一些临时桥梁,使得

无论在哪条道路施工,游客都能到达所有的旅游景点。那么问题来了:给你N个景点和M条双向边,

问:最少搭建几条临时桥梁,才能够使无论在哪条道路施工,都不会影响游客达到所有的旅游景点。


思路:

题目可以转变为:给你一个无向连通图,问至少添加几条边,才能变成双连通图。下边我们来考虑这

道题。当图中存在割边(桥)的时候,删掉它,显然构不成双连通图。割边的两端分属于两个边连通分

量。删除它原图就分成了两个边连通分量。所以必须在两个边连通分量之间再添加一条边(也就是题目

中说的临时桥梁,但不是刚才的割边),这两个边连通分量之间也成了双连通。那么,如果原图有多个

边连通分量,怎么添加临时边,才能使得任意两个边连通分量之间都成为双连通。

(1)找出原图的所有边连通分量。

(2)对原图进行缩点,将同属一个边连通分量的点看做一个点。

(3)求缩点后,最少添加几条双向边,使得全部点之间都能够直接到达。

关于第三步,参考下图来说明解决方法:

技术分享

原图G缩点后如右图所示。若使得所有边连通分量之间都成为双连通。就得使右图中A、B、C、D之间

能够相互连接。可以明显看出右图再添加2条边就可以满足要求。添加(A、B),使得A、B、D相互双连

通。再添加(B、C)或(A、C)使得A、B、C、D全部相互双连通。

那么第三步求出缩点后所有度数为1的点个数。结果ans = (缩点后度数为1的点个数+1) / 2。

参考博文:http://blog.csdn.net/lyy289065406/article/details/6762370


AC代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
const int MAXN = 1100;
const int MAXM = 5500;

struct EdgeNode
{
    int to;
    int next;
}Edges[MAXM];
int Head[MAXN];
int dfn[MAXN],low[MAXN],Stack[MAXN],degree[MAXN];
int m,id,scc,lay,M,N;

void AddEdges(int u,int v)
{
    Edges[id].to = v;
    Edges[id].next = Head[u];
    Head[u] = id++;
}

void TarjanBFS(int pos,int from)
{
    Stack[m++] = pos;
    dfn[pos] = low[pos] = ++lay;
    for(int i = Head[pos]; i != -1; i = Edges[i].next)
    {
        if(Edges[i].to == from)
            continue;
        if( !dfn[Edges[i].to] )
        {
            TarjanBFS(Edges[i].to,pos);
            low[pos] = min(low[pos],low[Edges[i].to]);
//            if( dfn[pos] < low[Edges[i].to] )
//            {
//                while(Stack[m--] != Edges[i].to);
//            }
        }
        else
            low[pos] = min(low[pos],low[Edges[i].to]);
    }
}

int main()
{
    int u,v;
    while(~scanf("%d%d",&N,&M))
    {
        memset(Head,-1,sizeof(Head));
        memset(dfn,0,sizeof(dfn));
        memset(low,0,sizeof(low));
        memset(degree,0,sizeof(degree));
        m = lay = scc = id = 0;

        for(int i = 0; i < M; ++i)
        {
            scanf("%d%d",&u,&v);
            AddEdges(u,v);
            AddEdges(v,u);
        }
        for(int i = 1; i <= N; ++i)
            if( !dfn[i] )
                TarjanBFS(1,-1);
        for(int i = 1; i <= N; ++i)
        {
            for(int j = Head[i]; j != -1; j = Edges[j].next)
            {
                if(low[i] != low[Edges[j].to])
                    degree[low[i]]++;
            }
        }

        int ans = 0;
        for(int i = 1; i <= N; ++i)
            if(degree[i] == 1)
                ans++;
        printf("%d\n",(ans+1)/2);
    }

    return 0;
}


郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。