题意:
大意说要在现有的图中加几条边使得整个图都是双联通分量。
题解:
跑一边Tarjan同时缩点,根据缩点完后的图,找出度为1的点的个数cnt,这个点肯定是桥的缩点,那么要满足题意,要添加的边数为:(cnt+1)/2;
#include<iostream> #include<math.h> #include<stdio.h> #include<algorithm> #include<string.h> #include<vector> #include<queue> #include<map> #include<set> using namespace std; #define B(x) (1<<(x)) typedef long long ll; void cmax(int& a,int b){ if(b>a)a=b; } void cmin(int& a,int b){ if(b<a)a=b; } const int oo=0x3f3f3f3f; const int MOD=1000000007; const int maxn=5100; const int maxm=21000; struct EDGE{ int v,next,c,f; }E[maxm]; int head[maxn],tol; int low[maxn],dfn[maxn]; int fa[maxn],bridge[maxm]; int id[maxn],d[maxn]; int g_cnt,bcnt,ID; void Init(){ memset(head,-1,sizeof head); tol=0; memset(low,0,sizeof low); memset(dfn,0,sizeof dfn); memset(d,0,sizeof d); g_cnt=bcnt=ID=0; for(int i=0;i<maxn;i++)fa[i]=i; } void add_edge(int u,int v){ E[tol].v=v; E[tol].next=head[u]; head[u]=tol++; } int Find(int x){ if(fa[x]==x)return x; return fa[x]=Find(fa[x]); } void Merge(int x,int y){ int fx=Find(x); int fy=Find(y); fa[fx]=fy; } void Tarjan(int u,int pre){ dfn[u]=low[u]=++g_cnt; for(int i=head[u];i!=-1;i=E[i].next){ int v=E[i].v; if(v==pre)continue; if(!dfn[v]){ Tarjan(v,u); if(low[v]<low[u]) low[u]=low[v]; if(low[v]>dfn[u]) bridge[bcnt++]=i; else Merge(u,v); }else if(dfn[v]<low[u]) low[u]=dfn[v]; } } void gao(int n){ memset(id,-1,sizeof id); for(int i=1;i<=n;i++){ int u=Find(i); if(id[u]==-1) id[u]=++ID; id[i]=id[u]; } for(int i=0;i<bcnt;i++){ int j=bridge[i]; int u=E[j^1].v; int v=E[j].v; u=id[u]; v=id[v]; d[u]++; d[v]++; } int cnt=0; for(int i=1;i<=ID;i++){ if(d[i]==1)cnt++; } printf("%d\n",(cnt+1)/2); } int main(){ //freopen("E:\\read.txt","r",stdin); int n,m,u,v; while(scanf("%d %d",&n,&m)!=EOF){ Init(); for(int i=1;i<=m;i++){ scanf("%d %d",&u,&v); add_edge(u,v); add_edge(v,u); } Tarjan(1,-1); gao(n); } return 0; }