題目:https://www.lydsy.com/JudgeOnline/problem.php?id=2730php
首先一遍tarjan找出割點,將圖縮點,這些大點中若是有隻包含一個割點的,那麼若是這個割點被去掉,則這個大點與圖不連通,因此這個大點內必須有一個出口;ios
而若是沒有割點,須要建兩個出口,以防止一個出口點被去掉;ide
方案數就是放出口的大點的size乘積;沒有割點則方案數爲C(m,2);spa
注意本身記錄點數。get
代碼以下:string
#include<iostream> #include<cstdio> #include<cstring> #include<vector> using namespace std; int const MAXN=505; vector<int>dcc[MAXN]; int t,n,m,siz,tim,ct,head[MAXN],dfn[MAXN],low[MAXN],num,k; long long ans; bool vis1[MAXN],vis2[MAXN],cut[MAXN]; struct N{ int to,next; N(int t=0,int n=0):to(t),next(n) {} }edge[MAXN<<2]; void add(int x,int y) { edge[++ct]=N(y,head[x]);head[x]=ct; edge[++ct]=N(x,head[y]);head[y]=ct; } void tarjan(int x,int f) { dfn[x]=low[x]=++tim; int fl=0; for(int i=head[x],u;i;i=edge[i].next) { if(edge[i].to==f)continue; if(!dfn[u=edge[i].to]) { fl++; tarjan(u,x); low[x]=min(low[x],low[u]); if(low[u]>=dfn[x])/*fl++,*/cut[x]=1; } else low[x]=min(low[x],dfn[u]); } if(!f&&fl==1)cut[x]=0; } int dfs(int x) { int siz=1; vis1[x]=1; for(int i=head[x],u;i;i=edge[i].next) { if(vis1[u=edge[i].to]||vis2[u])continue; if(!cut[u])siz+=dfs(u); // if(!cut[u])siz++,dfs(u); else if(!vis2[u])vis2[u]=1,num++; } return siz; } int main() { while(scanf("%d",&n)==1) { if(!n)return 0; t++;ct=0; tim=0;m=0;// memset(dfn,0,sizeof dfn); memset(low,0,sizeof low); memset(cut,0,sizeof cut); memset(head,0,sizeof head); memset(vis1,0,sizeof vis1); int x,y; for(int i=1;i<=n;i++) { scanf("%d%d",&x,&y); add(x,y); m=max(m,x);m=max(m,y); } for(int i=1;i<=m;i++) if(!dfn[i])tarjan(i,0); ans=1;k=0; for(int i=1;i<=m;i++) if(!vis1[i]&&!cut[i])//不能是割點 { num=0; memset(vis2,0,sizeof vis2); siz=dfs(i); if(num==1)k++,ans*=siz; } if(!k)k=2,ans=(long long)m*(m-1)/2;//m! printf("Case %d: %d %lld\n",t,k,ans); } return 0; }