您的位置:首页 > 其它

【HDU4612】 双连通分量求桥

2013-07-28 15:05 183 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4612

题目大意:给你一个无向图,问你加一条边后最少还剩下多少多少割边。

解题思路:好水的一道模板题。先缩点变成一颗树,再求树的最长直径,直径两端连一条边就是最优解了。

但是....我WA了一个下午.....没有处理重边。

重边的正确处理方法:只标记已经走过的正反边,而不限制已走过的点。换句话说就是可以经过重边再次走向父亲节点,而不能经过走过边的反向边返回父亲节点。

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <cstdio>
#include <queue>
#include <algorithm>
#include <cstring>
using namespace std;

const int maxn=222222;
const int maxm=2222222;
int  dfn[maxn], low[maxn], head[maxn], stack[maxn], instack[maxn], belong[maxn];
int  reach[maxm], next[maxm], sign[maxm];
int  visit[maxn];
int  top, Index, scnt, edge, pos, bridgenum;
int  n, m;
pair<int,int>num[maxm];

struct node
{
int u;
int dis;
int fa;
};
queue<node>q;

void init()
{
memset(head,-1,sizeof(head));
memset(dfn,0,sizeof(dfn));
memset(instack,0,sizeof(instack));
Index=top=edge=scnt=bridgenum=0;
}

void addedge(int u, int v)
{
sign[edge]=0, reach[edge]=v, next[edge]=head[u], head[u]=edge++;
sign[edge]=0, reach[edge]=u, next[edge]=head[v], head[v]=edge++;
}

void tarjan(int u)
{
stack[++top]=u;
dfn[u]=low[u]=++Index;
instack[u]=1;
for(int i=head[u]; i>=0; i=next[i])
{
if(sign[i]) continue;
sign[i]=1, sign[i^1]=1;  ///处理重边,只标记边,而不限制点
int v=reach[i];
if(!dfn[v])
{
tarjan(v), low[u]=min(low[u],low[v]);
if(dfn[u]<low[v]) bridgenum++;  ///求桥的数量
}
else if(instack[v]) low[u]=min(low[u],dfn[v]);
}
if(low[u]==dfn[u])
{
int v;
scnt++;   ///双连通分量的数量
do
{
v=stack[top--];
instack[v]=0;
belong[v]=scnt;
}
while(u!=v);
}
}

int bfs(int st)
{
int maxx=0;
while(!q.empty()) q.pop();
memset(visit,0,sizeof(visit));
node s, p;
s.u=st, s.dis=0, s.fa=-1;
q.push(s);
visit[s.u]=1;
while(!q.empty())
{
p=q.front();
q.pop();
for(int i=head[p.u]; i>=0; i=next[i])
{
int v=reach[i];
if(v==p.fa) continue;
s.u=v, s.dis=p.dis+1, s.fa=p.u;
if(!visit[s.u])
{
visit[s.u]=1, q.push(s);
if(s.dis>maxx)
{
maxx=s.dis;
pos=s.u;
}
}
}
}
return maxx;
}

void Solve()
{
memset(head,-1,sizeof(head));
edge=0;
for(int i=1; i<=m; i++)
{
int u=num[i].first, v=num[i].second;
int x=belong[u], y=belong[v];
if(x!=y) addedge(x,y);
}
bfs(1);
int ans=bfs(pos);
cout << bridgenum-ans <<endl;
}

int main()
{
while(cin >> n >> m, n+m)
{
init();
for(int i=1; i<=m; i++)
{
int u, v;
scanf("%d%d",&u,&v);
num[i].first=u, num[i].second=v;
addedge(u,v);
}
for(int i=1; i<=n; i++)
if(!dfn[i]) tarjan(i);
Solve();
}
return 0;
}

/*
10 11
1 2
2 3
3 4
2 4
3 6
5 10
5 7
7 8
8 9
7 9
3 5
*/


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: