hdu5305 Friends[状压dp]

Friends

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 2329    Accepted Submission(s): 1150


 

Problem Description

There are n people and m pairs of friends. For every pair of friends, they can choose to become online friends (communicating using online applications) or offline friends (mostly using face-to-face communication). However, everyone in these n people wants to have the same number of online and offline friends (i.e. If one person has x onine friends, he or she must have x offline friends too, but different people can have different number of online or offline friends). Please determine how many ways there are to satisfy their requirements. 

 

 

Input

The first line of the input is a single integer T (T=100), indicating the number of testcases. 

For each testcase, the first line contains two integers 
n (1≤n≤8) and m (0≤mn(n−1)2), indicating the number of people and the number of pairs of friends, respectively. Each of the next m lines contains two numbers x and y, which mean x and y are friends. It is guaranteed that xy and every friend relationship will appear at most once. 

 

 

Output

For each testcase, print one number indicating the answer.

 

 

Sample Input

2

3 3

1 2

2 3

3 1

4 4

1 2

2 3

3 4

4 1

 

 

Sample Output

0

2

 

 

Author

XJZX

 

 

Source

2015 Multi-University Training Contest 2

 

 

Recommend

wange2014   |   We have carefully selected several similar problems for you:  6022 6021 6020 6019 6018 

 

题目大意:

给出遮个点遭条边逨n 8,每个边可能是黑色也可能是白色,求每个点相连的边黑边和白边的数量都相等的图有几种。

思路:

这个题大家都是用搜索逫剪枝做的,但是知道了这个题的遤遰做法以后真的是让人感叹啊!

首先,若某个点的度是奇数,就直接不可能了,然后再考虑遤遰的状态!

我们按照边的顺序一条一条染色(默认所有边原来是白色的),遦遛適遝遛達遝表示染完(染黑或者染白)

第適条边,状态为達的时候的方法数。

達由遮个两位的二进制数组成,每两位表示一个点所连的黑边的数目,转移什么的都是显而易见的

事情,不再多说!

思考:

之所以把这个本来是搜索的题的状压遤遰的做法放在这里,主要是因为其体现了状压只是一个手段

这一点,而且从这个题来看转移的手段是非常灵活的,比如在插头遤遰里常见的四进制,和这个题里面

的两位二进制,其实有异曲同工之处!

当然,这种情况下,对位运算的灵活运用就是蛮重要的了,其实呢,个人觉得只要心中把这个数

当成是二进制数想清楚该怎样使用位运算还是比较容易的!

 

#include<cstdio>
#include<cstring>
using namespace std;
const int N=51;
int f[N][1<<17];
int n,m,T,inc[N];
struct edge{int x,y;}e[N<<1];
int main(){
//    freopen("a.in","r",stdin);
    for(scanf("%d",&T);T;T--){
        scanf("%d%d",&n,&m);
        memset(inc,0,sizeof inc);
        for(int i=1;i<=m;i++){
            scanf("%d%d",&e[i].x,&e[i].y);e[i].x--,e[i].y--;
            inc[e[i].x]++;
            inc[e[i].y]++;
        }
        bool b=0;
        for(int i=0;i<n;i++) if(inc[i]&1){b=1;puts("0");break;}
        if(b) continue;
        memset(f,0,sizeof f);
        f[0][0]=1;
        int ALL=1<<(n<<1);
        for(int i=1;i<=m;i++){
            for(int S=0;S<ALL;S++){
                f[i][S]+=f[i-1][S];
                int u=e[i].x;
                int v=e[i].y;
                int tu=(S>>(u<<1))&3;
                int tv=(S>>(v<<1))&3;
                if(tu+1>(inc[u]<<1)) continue;
                if(tv+1>(inc[v]<<1)) continue;
                int su=tu+1;
                int sv=tv+1;
                int S0=S^(tu<<(u<<1))^(tv<<(v<<1));
                S0=S0|(su<<(u<<1))^(sv<<(v<<1));
                f[i][S0]+=f[i-1][S];
            }
        }
        int S=0;
        for(int i=n-1;~i;i--) S<<=2,S|=inc[i]>>1;
        printf("%d
",f[m][S]);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/shenben/p/6707411.html