UVALive 6907 Body Building tarjan
Body Building
题目连接:
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;
}