您的位置:首页 > 其它

[POJ3177]Redundant Paths 边双连通分量 做题笔记

2016-03-08 23:06 453 查看
题目来源:http://poj.org/problem?id=3177

解题思路:/article/6913509.html

分析:在同一个边双连通分量中,任意两点都有至少两条独立路可达,所以同一个边双连通分量里的所有点可以看做同一个点。

缩点后,新图是一棵树,树的边就是原无向图的桥。

现在问题转化为:在树中至少添加多少条边能使图变为双连通图。

结论:添加边数=(树中度为1的节点数+1)/2

具体方法为,首先把两个最近公共祖先最远的两个叶节点之间连接一条边,这样可以把这两个点到祖先的路径上所有点收缩到一起,因为一个形成的环一定是双连通的。然后再找两个最近公共祖先最远的两个叶节点,这样一对一对找完,恰好是(leaf+1)/2次,把所有点收缩到了一起。

其实求边双连通分量和求强连通分量差不多,每次访问点的时候将其入栈,当low[u]==dfn[u]时就说明找到了一个连通的块,则栈内的所有点都属于同一个边双连通分量,因为无向图要见反向边,所以在求边双连通分量的时候,遇到反向边跳过就行了。

不过貌似这位博主的代码有点。。问题

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int N=5005,M=10005;
int head
,ver[M<<1],e[M<<1],next[M<<1];
int dfn
,low
,bel
,q[N<<1],ind
,fa
;
bool inq
;
int tot=1,cnt=0,top=0,scc=0,n,m;

void add (int u,int v) {
ver[++tot]=v;next[tot]=head[u];head[u]=tot;
ver[++tot]=u;next[tot]=head[v];head[v]=tot;
}

void Tarjan (int x) {
low[x]=dfn[x]=++cnt;
q[++top]=x;inq[x]=1;
int v;
for (int i=head[x];i;i=next[i]) {
fa[ver[i]]=x;
if (!dfn[v=ver[i]])
Tarjan(v),low[x]=min(low[x],low[v]);
else if (inq[v] && fa[x]!=v)
low[x]=min(low[x],dfn[v]);
}
int now=0;
if (dfn[x]==low[x]) {
scc++;
while (top&&x!=now) {
now=q[top--];
bel[now]=scc;
inq[now]=0;
}
}
}

int main () {
int u,v,w;
scanf("%d%d",&n,&m);
for (int i=0;i<m;i++) {
scanf("%d%d",&u,&v);
add(u,v);
}
for (int i=1;i<=n;i++)
if (!dfn[i])
Tarjan(1);
for (int i=1;i<=n;i++)
for (int j=head[i];j;j=next[j])
if (bel[i]!=bel[ver[j]])
ind[bel[i]]++;
int sum=0;
for (int i=1;i<=n;i++) //
if (ind[i]==1) sum++;
int ans=(sum+1)/2;
printf("%d\n",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: