您的位置:首页 > 其它

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

2015-02-17 21:37 441 查看
题目链接:

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: