把无向图的边双联通块缩成一个点,然后建立一棵树。
假如树中度数为1的点的个数为x个。
那么结果为(x+1)/2.
#include<stdio.h> #include<string.h> #include<algorithm> #include<iostream> using namespace std; #define maxn 5500 #define maxm 22000 #define mem(a,b) (memset(a,b,sizeof(a))) struct gra { int n,m; struct list{int u,v,next;}edge[maxm]; int head[maxn],num,vis[maxm]; int dnf[maxn],low[maxn],times; int cnt[maxn]; void init(int x,int y){ num=0;times=1; n=x;m=y; mem(head,-1);mem(dnf,0);mem(low,0); mem(vis,0);mem(cnt,0); } void add(int u,int v){ edge[num].u=u;edge[num].v=v; edge[num].next=head[u];head[u]=num++; } void tarjan(int x) { dnf[x]=low[x]=times++; for(int i=head[x];i!=-1;i=edge[i].next) { int y=edge[i].v; if(vis[i])continue; vis[i]=vis[i^1]=1; if(!dnf[y]) { tarjan(y); low[x]=min(low[x],low[y]); } else { low[x]=min(low[x],dnf[y]); } } } void start() { tarjan(1); for(int x=1;x<=n;x++) { for(int i=head[x];i!=-1;i=edge[i].next) { int y=edge[i].v; if(low[x]!=low[y]) { cnt[low[y]]++; } } } int ans=0; for(int i=1;i<=n;i++) { if(cnt[i]==1)ans++; } cout<<(ans+1)/2<<endl; } }G; int main() { int n,m,i,a,b; while(~scanf("%d%d",&n,&m)) { G.init(n,m); for(i=1;i<=m;i++) { scanf("%d%d",&a,&b); G.add(a,b); G.add(b,a); } G.start(); } return 0; }