标签:
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 ;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
hdu5305(2015多校2)--Friends(状压,深搜)
标签:
原文地址:http://blog.csdn.net/winddreams/article/details/47037727