无向图双连通分量
昨天刚复习了一波割顶和桥,tarjin相关,今天就写了一道233
算是比较简单的题
大概直接将目前图中所以边-双连通都缩为一个点,然后得到一颗树
设这颗树上所有出度为1的点的个数为sum
容易证明答案为(sum+1)/2
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<string>
#include<map>
#include<algorithm>
using namespace std;
int n,r;
int to[2005],head[1005],_next[2005];
int e[1005][1005],Sta[1005],End[1005],que[1005];
int nam[1005],fa[1005];
int kp[1005];
int cnt=0;
int sum,ans=0,tot=0,tnt=0;
int sign;
void add(int x,int y)
{
cnt++;
to[cnt]=y;
_next[cnt]=head[x];
head[x]=cnt;
}
void lcr(int x)
{
int i,j,k,l;
cnt++;
Sta[x]=End[x]=cnt;
tot++;
que[tot]=x;
for(i=head[x];i;i=_next[i]){
if(to[i]==fa[x])continue;
if(Sta[to[i]]==0){
fa[to[i]]=x;
lcr(to[i]);
End[x]=min(End[to[i]],End[x]);
}
else if(!nam[to[i]])End[x]=min(End[x],Sta[to[i]]);
}
if(Sta[x]==End[x]){
tnt++;
k=que[tot];
while(k!=x){
tot--;
nam[k]=tnt;
k=que[tot];
}
nam[k]=tnt;
tot--;
}
}
int main()
{
int i,j,k,l,x,y;
scanf("%d%d",&n,&r);
for(i=1;i<=r;i++){
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
cnt=0;
lcr(1);
for(i=1;i<=n;i++)
for(j=head[i];j;j=_next[j]){
if((!e[nam[i]][nam[to[j]]])&&nam[i]!=nam[to[j]]){
e[nam[i]][nam[to[j]]]=1;
e[nam[to[j]]][nam[i]]=1;
kp[nam[i]]++;
kp[nam[to[j]]]++;
}
}
for(i=1;i<=tnt;i++)if(kp[i]==1)ans++;
ans=(ans+1)/2;
printf("%d",ans);
return 0;
}