UVALive 6907 Body Building tarjan

Body Building

题目连接:

https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4919

Description

Bowo is fed up with his body shape. He has a tall posture, but he’s very skinny. No matter how much
he eats, he never gains any weight. Even though he is a computer geek (and he loves it), he wants
a pretty and non-geek girlfriend. Unfortunately, most girls in his surrounding do not like skinny and
unattractive guy. Therefore, Bowo has decided to gain some muscles in his body; he joined a fitness
club and begun to do some body building exercises.
There are a lot of exercise equipments in a fitness club, and usually there should be weightlifting
equipments such as barbell and dumbbell (barbell with shorter rod). Upon seeing a dumbbell, Bowo
cannot help but imagining graphs which are similar to a dumbbell. A graph — which later referred as
“connected component” — of N nodes is called a dumbbell if it fulfills all the following conditions:
(i) All nodes in the graph can be partitioned into two disjoint sets P and Q which have equal size,
i.e. N/2 nodes each.
(ii) Both induced subgraph of P and Q are complete graphs.
(iii) P and Q are connected by exactly one edge.
Informally, a dumbbell is obtained by connecting two equal size complete graphs with an edge.
For example, consider graph A in Figure 1 with 10 nodes and 21 edges. There are two disjoint
complete graphs of size 5 which are connected by an edge. Therefore, this graph is a dumbbell. Graph
B and C are also dumbbells. Graph D, on the other hand, is not.
Figure 1.
Given a graph (which might be disconnected), determine how many connected components which
are dumbbells. A connected component is a connected subgraph which no vertex can be added and
still be connected.

Input

The first line of input contains an integer T (T ≤ 50) denoting the number of cases. Each case begins
with two integers: N and M (1 ≤ N ≤ 100; 0 ≤ M ≤ 4, 950) denoting the number of nodes and edges
in the graph respectively. The nodes are numbered from 1 to N. The following M lines each contains
two integer: a and b (1 ≤ a, b ≤ N; a ̸= b) representing an undirected edge connecting node a and node
b. You are guaranteed that each pair of nodes has at most one edge in the graph.

Output

For each case, output ‘Case #X: Y ’, where X is the case number starts from 1 and Y is the number
of connected components which are dumbbells for the respective case.
Explanation for 1st sample case:
There is only one node in the graph; a dumbbell requires at least two nodes.
Explanation for 2nd sample case:
Both connected components are dumbbells: {1, 2} and {3, 4}.
Explanation for 3rd sample case:
There are two connected components: {1, 2, 3, 4, 5, 6}, and {7, 8, 9, 10}, and both of them are
dumbbells. The first one is dumbbell with complete graph of size 3, while the second one has size of 2.
Explanation for 4th sample case:
There are four connected components: {1, 2}, {3, 4}, {5, 6} and {7, 8, 9}. Only the first three are
dumbbells.

Sample Input

4
1 0
4 2
1 2
3 4
10 10
1 2
1 3
2 3
3 4
4 5
5 6
4 6
7 8
8 9
9 10
9 5
1 2
3 4
5 6
7 8
8 9

Sample Output

Case #1: 0
Case #2: 2
Case #3: 2
Case #4: 3

Hint

题意

给你个无向图,问里面有多少个子图,满足里面可以分成P,Q两个连通块,且这两个PQ都是完全图,且两个图都由一条边连接,且俩完全图的size相同。

题解:

跑桥,然后看看桥两边的连通块长什么样子,然后特判断一下4个点的情况……

代码

#include <bits/stdc++.h>
#define rep(a,b,c) for(int (a)=(b);(a)<=(c);++(a))
#define drep(a,b,c) for(int (a)=(b);(a)>=(c);--(a))
#define pb push_back
#define mp make_pair
#define sf scanf
#define pf printf
#define two(x) (1<<(x))
#define clr(x,y) memset((x),(y),sizeof((x)))
#define dbg(x) cout << #x << "=" << x << endl;
#define lowbit(x) ((x)&(-x))
const int mod = 1e9 + 7;
int mul(int x,int y){return 1LL*x*y%mod;}
int qpow(int x , int y){int res=1;while(y){if(y&1) res=mul(res,x) ; y>>=1 ; x=mul(x,x);} return res;}
inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;}
using namespace std;
const int maxn = 100 + 15;
int mat[maxn][maxn],N,M,vis[maxn],low[maxn],dfn[maxn],ti,label[maxn],rt,head[maxn],tot,sz[maxn];
vector < int > block,dcc[maxn];
stack < int > sp;

struct edge{
    int v , nxt , isbrige;
}e[maxn * maxn * 5];

void dfs( int x ){
	if( vis[x] ) return ;
	vis[x] = 1;
	block.pb( x );
	for(int i = head[x] ; ~i ; i = e[i].nxt){
		int v = e[i].v;
		dfs( v );
	}
}


void predfs( int x , int pr ){
	dfn[x] = low[x] = ++ ti;
	sp.push( x );
	for(int i = head[x] ; ~i ; i = e[i].nxt){
		int v = e[i].v;
		if( i == ( pr ^ 1 ) ) continue;
		if( !dfn[v] ){
			predfs( v , i );
			low[x] = min( low[x] , low[v] );
			if( low[v] > dfn[x] ) e[i].isbrige = e[i ^ 1].isbrige = 1;
		}else if( dfn[v] < dfn[x] ) low[x] = min( low[x] , dfn[v] );
	}
	if( low[x] == dfn[x] ){
		int u;
		++ rt;
		do{
			u = sp.top() ; sp.pop();
			label[u] = rt;
		}while( u != x );
	}
}

bool judge( vector < int > & a ){
	for(int i = 0 ; i < a.size() ; ++ i)
		for(int j = i + 1 ; j < a.size() ; ++ j)
			if( mat[a[i]][a[j]] == 0 ) 
				return false;
	return true;
}

int solve( int base ){
	block.clear();
	dfs( base );
	if( block.size() == 4 ){
		vector < int > dp;
		for( auto it : block ) dp.pb( sz[it] );
		sort( dp.begin() , dp.end() );
		if( dp[0] == 1 && dp[1] == 1 && dp[2] == 2 && dp[3] == 2 ) return true;
		return false;
	}
	ti = rt = 0;
	predfs( base , 999999999 );	int bridgenum = 0;
	for(auto it : block){
		for(int i = head[it] ; ~i ; i = e[i].nxt) if( e[i].isbrige ) ++ bridgenum;
	}
	bridgenum >>= 1;
	if( bridgenum == 0 || bridgenum > 3 ) return 0;
	if( (int)block.size() & 1 ) return 0;
	for(int i = 1 ; i <= rt ; ++ i) dcc[i].clear();
	for(auto it : block) dcc[label[it]].pb( it );
	if( bridgenum == 1 ){
		if( dcc[1].size() != dcc[2].size() ) return 0 ;
		if( !judge(dcc[1]) || !judge( dcc[2] )) return 0;
	}else if( bridgenum == 2 ){
		return 0;
	}else if( bridgenum == 3 ){
		if( block.size() != 4 ) return 0;
	}
    return 1;
}


void link( int u , int v ){
	e[tot].isbrige=0,e[tot].v=v,e[tot].nxt=head[u],head[u]=tot++;
}

int main(int argc,char *argv[]){
	int T=read(),cas=0;
	while(T--){
		N=read(),M=read();
		rep(i,1,N) rep(j,1,N) mat[i][j]=0;
		clr(head,-1);
		clr(sz,0);
		clr(label,0);
		clr(dfn,0);
		clr( vis , 0 );
		tot = 0;
		rep(i,1,M){
			int u , v ;
			sf("%d%d",&u,&v);
			mat[u][v] = mat[v][u] = 1;
			sz[u] ++ ;
			sz[v] ++ ;
			link( u , v );
			link( v , u );
		}
		int ans = 0;
		rep(i,1,N) if(!vis[i]) ans += solve( i );
		pf("Case #%d: %d\n", ++ cas , ans );
	}
	return 0;
}
posted @ 2016-08-03 18:35  qscqesze  阅读(362)  评论(0编辑  收藏  举报