2 3 3 1 2 2 3 3 1 4 4 1 2 2 3 3 4 4 1
0 2
题目大意:给出n个人,m个朋友关系,每个关系可以为在线或离线,问如果要让每个人的在线朋友数和离线朋友数相同,那么关系组成有多少种情况。(n<=8,m<=n*(n-1)/2)
由题目可以推出如果m=25,26,27,28,那么n一定为8,那么总会有一个人的朋友数位奇数,关系组成情况数为0
现在m最大为24,那么就很好做了,可以对关系进行状压(0:离线,1:在线),或者直接深搜,方式都是一样的,遍历所有的情况。
注意:m为24时数目还是比较大的,需要剪枝一下,可以在每个人的关系中选出一条,这一条边是不用枚举的,因为可以由已经推出的情况来决定这条边是不是在线,这样至少会减少1条边,每减少一条边,那么搜索的复杂度就会减少一半。
#include <cstdio> #include <cstring> #include <algorithm> using namespace std ; struct node{ int u , v ; }p[30]; int n , m ; int sum[10] , num[10] , cnt , flag[10] , vis[10] ; void dfs(int s) { int i ; if( s == m ) { for(i = 1 ; i <= n ; i++) { if( sum[i]/2 == num[i]+1 && i < flag[i] ) { num[i]++ ; num[ flag[i] ]++ ; vis[i] = 1 ; } if( sum[i]/2 != num[i] ) break ; } if( i > n ) cnt++ ; for(i = 1 ; i <= n ; i++) { if( vis[i] ) { num[i]-- ; num[ flag[i] ]-- ; vis[i] = 0 ; } } return ; } dfs(s+1) ; num[ p[s].u ]++ ; num[ p[s].v ]++ ; dfs(s+1) ; num[ p[s].u ]-- ; num[ p[s].v ]-- ; } int main() { int t , i ; int u , v , cid ; //freopen("f.in","r",stdin) ; //freopen("1.txt","w",stdout) ; scanf("%d", &t) ; while( t-- ) { scanf("%d %d", &n, &m) ; memset(sum,0,sizeof(sum)) ; memset(num,0,sizeof(num)) ; memset(flag,0,sizeof(flag)) ; memset(vis,0,sizeof(vis)) ; cid = cnt = 0 ; for(i = 0 ; i < m ; i++) { scanf("%d %d", &u, &v) ; sum[u]++ ; sum[v]++ ; if( flag[u] == 0 && flag[v] == 0 ) { flag[u] = v ; flag[v] = u ; } else { p[cid].u = u ; p[cid++].v = v ; } } m = cid ; for(i = 1 ; i <= n ; i++) if( sum[i]%2 ) break ; if( i <= n ) { printf("0\n") ; continue ; } /*if( n == 8 && m == 24 ) { printf("2648\n") ; continue ; }*/ dfs(0) ; printf("%d\n", cnt) ; } return 0 ; }