/***
双联通缩点,再加几条边能使原图成为全部双联通
和强联通的区别在于,一个是有向图,一个是无向图
此题,原题连通
***/
#include<cstdio>
#include<cstring>
#include<vector>
#include<iostream>
using namespace std;
const int M = 10008;
int low[M],t,dfs[M],instack[M],odd[M],index,bet,cn,stack[M];
int tmp,num[M],top;
struct{
int head;
}H[M];
struct{
int u,v,next;
}E[M*2];
void add(int u,int v)
{
E[top].v = v;
E[top].next = H[u].head;
H[u].head = top++;
}
void init()
{
memset(E,-1,sizeof(E));
memset(H,-1,sizeof(H));
memset(low,0,sizeof(low));
memset(dfs,0,sizeof(dfs));
memset(instack,0,sizeof(instack));
memset(num,0,sizeof(num));
tmp = cn = bet = index = top = 0;
}
void tarjan(int u,int fa)
{
dfs[u] = low[u] = ++index;
stack[++cn] = u;
instack[u] = 1;
for(int i=H[u].head;i!=-1;i=E[i].next)
{
int v = E[i].v;
if(i == (fa^1))continue;
if(!dfs[v])
{
tarjan(v,i);
low[u] = min(low[u],low[v]);
}
else
if(instack[v])
low[u] = min(low[u],dfs[v]);
}
if(low[u]==dfs[u])
{
bet++;
do
{
t = stack[cn--];
instack[t] = 0;
num[t] = bet; // 类似于强联通分量
}while(t!=u);
}
}
vector<int>V[10000];
int main()
{
int n,m;
int u,v;
while(~scanf("%d%d",&n,&m))
{
init();
while(m --)
{
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
for(int i=1;i<=n;i++)
if(!dfs[i]) tarjan(i,-1);
for(int i=1;i<=n;i++)
{
for(int j=H[i].head;j!=-1;j = E[j].next)
{
int sv = E[j].v;
if(num[i]!=num[sv])
{
V[num[i]].push_back(num[sv]);
}
}
}
int sum =0;
for(int i=1;i<=bet;i++)
{
if(V[i].size() == 1)
sum++;
}
cout<<(sum+1)/2<<endl;
}
}
poj 3177 双联通缩点
最新推荐文章于 2021-04-21 20:32:24 发布