/********************************************************************
** @file poj3177.cpp
** @author liuke
** @date Sun May 1 09:49:13 2011
** @brief 边的双连通分量问题
首先是根据割边求出所有点的双连通分量,然后进行缩点。
然后对缩点后的图看度数为一的顶点可以有多少个。然后添加的边数即为(n+1)/ 2条。
**
**
********************************************************************/
#include <iostream>
#include <vector>
#include <cstdio>
#include <cstring>
#define MAXN 5001
#define WHITE 0
#define GRAY 1
#define BLACK 2
using namespace std;
vector<int> g[MAXN];
int f,r, c[MAXN], dfn[MAXN], low[MAXN], cnt;
int t[MAXN];
void input(){
cin>>f>>r;
int u,v;
for(int i=0;i<r;++i){
cin>>u>>v;
g[u].push_back(v);
g[v].push_back(u);
}
}
void dfs(int v,int f){/*f 为v的父节点*/
bool flag=true;
c[v]=GRAY;
low[v]=dfn[v]=++cnt;
for(int i=0;i<g[v].size();++i){
int u=g[v][i];
if(u==f && flag==true){
flag=false;continue;/*防止往回走*/
}
if(c[u]==WHITE)
dfs(u,v);
low[v]=min(low[v],low[u]);/*缩点*/
}
c[v]=BLACK;
}
int solve(){
cnt=0;
memset(t,0,sizeof(t));
memset(c,WHITE,sizeof(c));
dfs(1,-1);
for(int i=1;i<=f;++i){
for(int j=0;j<g[i].size();++j)
if(low[i]!=low[g[i][j]])
t[low[i]]++;/*缩点后的 对应的各个双连通分支的度加1,low[i]代表了各个连通分支*/
}
int ans=0;
for(int i=1;i<=f;++i)
if(t[i]==1)ans++;/*统计度为1的节点,缩点后的分支会算一个节点,因为它们的low值相同*/
return (ans+1)/2;
}
int main(int argc, char *argv[])
{
input();
cout<<solve()<<endl;
return 0;
}
poj 3177 边的双连通分支
最新推荐文章于 2021-04-21 20:32:24 发布