题目链接
http://poj.org/problem?id=3177
题意
某人要修路,保证任意两个点之间可以有至少两条不同的路线到达,求至少需要修的路的数量(加的边数)。给的图是连通的
思路
其实就是边-双连通图的定义:这种图任意两个顶点之间至少存在两条无公共边的路径。
所以就是需要加最少的边,使图变成边双连通图。具体做法是先双连通分量缩点成树,找出叶子节点的个数leaf。答案为(leaf+1)/2.做法与pojpoj 3352 Road Construction 一样。唯一的区别是这题图是有重边的,只需在tarjan缩点时处理一下即可。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<string>
#include<queue>
#include<stack>
#include<set>
#include<map>
#define ll long long
using namespace std;
const int INF = ( 2e9 ) + 2;
const ll maxn = 5e3+10;
const int maxm = 2*1e4+10;
vector<int> g[maxn];
int dfn[maxn],low[maxn],Belong[maxn],Stack[maxn],In[maxn];
int index,bcc,top;
void tarjan(int u,int fa)
{
dfn[u]=low[u]=++index;
Stack[top++]=u;
int f=1;
for(int i=0,L=g[u].size();i<L;i++)
{
int v=g[u][i];
if(f&&v==fa)
{
f=0;
continue;
}
if(!dfn[v])
{
tarjan(v,u);
low[u]=min(low[u],low[v]);
}
else
low[u]=min(low[u],dfn[v]);
}
if(low[u]==dfn[u])
{
int x;
bcc++;
do
{
x=Stack[--top];
Belong[x]=bcc;
}while(x!=u);
}
}
int solve(int n)
{
memset(dfn,0,sizeof(dfn));
memset(In,0,sizeof(In));
index=bcc=top=0;
tarjan(1,-1);
for(int u=1;u<=n;u++)
{
for(int j=0,L=g[u].size();j<L;j++)
{
int v=g[u][j];
if(Belong[u]!=Belong[v])
{
In[Belong[v]]++;
}
}
}
int leaf=0;
for(int i=1;i<=bcc;i++)
if(In[i]==1)leaf++;
return (leaf+1)/2;
}
int main()
{
int n,m,u,v;
while(~scanf("%d%d",&n,&m))
{
for(int i=1;i<=n;i++)g[i].clear();
for(int i=0;i<m;i++)
{
scanf("%d%d",&u,&v);
g[u].push_back(v);
g[v].push_back(u);
}
printf("%d\n",solve(n));
}
}

本文介绍了一种解决特定图论问题的方法:如何通过添加最少数量的边使得图成为边双连通图。该文详细阐述了使用Tarjan算法进行双连通分量缩点的过程,并最终计算出所需添加边数的解决方案。
2230

被折叠的 条评论
为什么被折叠?



