题目
BUPT Spring Training 6 4.06
题意:
给你一个图,求有多少个点对,之间的路径有且只有一条(点可以重复访问边不可以)。
解法:
删掉所有的双连通子图,对剩下的每一个连通块,若有n个结点,则有n*(n-1)/2个点对
//Time:185ms //Memory:0KB //Length:2039B #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <algorithm> #include <string> #include <vector> #include <map> #include <queue> #include <set> #define DBLE 1e-8 #define PI 3.1415926535898 #define INF 1000000000 #define MAXN 200010 #define MP(x,y) (make_pair((x),(y))) using namespace std; int he[MAXN],to[MAXN],nex[MAXN],top; int dfn[MAXN],low[MAXN],ttop,sta[MAXN],stop; bool col[MAXN]; void add(int u,int v) { nex[top]=he[u]; to[top]=v; he[u]=top++; } void tarjan(int h,int fa) { int tmp; dfn[h]=low[h]=ttop++; sta[stop++]=h; for(int i=he[h];i!=-1;i=nex[i]) if(!dfn[to[i]]) { tarjan(to[i],h); low[h]=min(low[h],low[to[i]]); } else if(fa!=to[i]) low[h]=min(low[h],dfn[to[i]]); tmp=stop; if(dfn[h]<=low[h]) { do { --stop; if(sta[tmp-1]!=h) col[sta[stop]]=1; }while(sta[stop]!=h); } } int bfs(int h) { if(col[h]) return 0; int cnt=0; queue<int> que; que.push(h); col[h]=1; while(que.size()) { h=que.front(); que.pop(); ++cnt; for(int i=he[h];i!=-1;i=nex[i]) if(!col[to[i]]) que.push(to[i]),col[to[i]]=1; } return cnt; } int main() { //freopen("I:\\MyDocument\\Code\\input.txt","r",stdin); int ncase,n,m,a,b,c,tmp,ans; scanf("%d",&ncase); for(int h=1;h<=ncase;++h) { ans=0; top=0; scanf("%d%d",&n,&m); memset(he,-1,sizeof(he)); memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); for(int i=0;i<m;++i) scanf("%d%d",&a,&b),add(a,b),add(b,a); memset(col,0,sizeof(col)); ttop=1; for(int i=1;i<=n;++i) if(!dfn[i]) stop=0,tarjan(i,-1); for(int i=1;i<=n;++i) { tmp=bfs(i); if(tmp) ans+=tmp*(tmp-1)/2; } printf("Case #%d: %d\n",h,ans); } return 0; }