第一道双联通的题目,求加几条边让原图成一个双联通图,求出度数为1的双联通分量的个数+1/2、
Low[u]为u或u的子树中能通过非父子边追溯到的最早的节点,即DFS序号最小的节点的序号
#include<stdio.h> #include<stack> #include<string.h> #define N 5010 using namespace std; int n,m,first[N],num,low[N],dfs[N],idx,ans,vis[N],degree[N],belong[N]; struct edge { int ed,next; }E[10010]; void addedge(int x,int y) { E[num].ed=y; E[num].next=first[x]; first[x]=num++; } stack<int>Q; void Tarjan(int u,int father) { low[u]=dfs[u]=idx++; vis[u]=1; Q.push(u); for(int p=first[u];p!=-1;p=E[p].next) { int v=E[p].ed; if(v==father){continue;} if(!vis[v])Tarjan(v,u); low[u]=low[u]>low[v]?low[v]:low[u]; } int x; if(low[u]==dfs[u]) { do { x=Q.top(); Q.pop(); vis[x]=0; belong[x]=ans;//缩点 }while(x!=u); ans++; } } int judge(int x,int y) { for(int p=first[x];p!=-1;p=E[p].next) if(E[p].ed==y) return 0; return 1; } int main() { int i,x,y,sum; while(scanf("%d%d",&n,&m)!=-1) { memset(first,-1,sizeof(first)); num=0; for(i=0;i<m;i++) { scanf("%d%d",&x,&y); if(judge(x,y)==1)//去掉重边 { addedge(x,y); addedge(y,x); } } memset(vis,0,sizeof(vis)); idx=ans=0; Tarjan(1,0); memset(degree,0,sizeof(degree)); for(i=1;i<=n;i++) { for(int p=first[i];p!=-1;p=E[p].next) { int v=E[p].ed; if(belong[i]!=belong[v]) degree[belong[v]]++; } } sum=0; for(i=0;i<ans;i++) if(degree[i]==1)//度为1的点 sum++; //printf("%d\n",sum); printf("%d\n",(sum+1)/2); } return 0; }