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;
}
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;
}
相关文章推荐
- POJ 3352|Road Construction|边双联通分量|Tarjan
- POJ 3352 Road Construction 双联通分量 难度:1
- POJ 3352 Road Construction 边双联通分量
- 【POJ 3352】 Road Construction(边联通分量入门)
- POJ 3352 Road Construction&& POJ 3177 Redundant Paths 双联通分量
- Road Construction+求双联通分量、割点、桥+POJ
- POJ 3352--Road Construction【无向图增加最少的边成为边双连通图 && tarjan求ebc && 缩点构造缩点树】
- POJ 3352 Road Construction POJ 3177 Redundant Paths(边双连通图 Tarjan+缩点)
- poj 3353 Road Construction tarjan 边双联通分支 缩点+结论
- Tarjan算法求解桥和边双连通分量(附POJ 3352 Road Construction解题报告
- POJ 3352 Road Construction(边双连通分量,桥,tarjan)
- Tarjan算法求解桥和边双连通分量(附POJ 3352 Road Construction解题报告)
- poj 3352 tarjan边双联通分量
- POJ 3352 Road Construction POJ 3177Redundant Paths(Tarjan缩点)
- POJ-3352 Road Construction,tarjan缩点求边双连通!
- POJ3352 Road Construction 双连通分量和桥 tarjan
- POJ3352 Road Construction 双连通分量和桥 tarjan
- POJ-3352 Road Construction (边双连通分量[Tarjan])
- POJ 3352 Road Construction (边双连通分量 Tarjan缩点)
- poj 3352 Road Construction (tarjan)