题目:http://acm.hdu.edu.cn/showproblem.php?pid=5305
题意:给定N个人和M条朋友关系,是朋友关系的两个人之间有两种联系方式online和offline。使每个人的online的数量和offline的数量相等,求方案数。
分析:由于M<=28,暴力枚举的话2^28很大,会超时。可以考虑把所有的状态平分成两半,即枚举前面M/2条关系,暴力求出前面的2^(M/2)种状态,然后枚举后面M/2条关系,暴力求出后面2^(M/2)种状态,再枚举后面一半的状态,对于每一种状态直接在前面一半的状态里面找出满足条件的即可。找状态用dfs比二进制枚举要快,查询的话map比hash方便。。。
代码:
#include <iostream> #include <vector> #include <cstdio> #include <cstring> #include <map> using namespace std; int N,M,cnt[20],buf[20],f[20],ans,tp; struct node { int a,b; }e[200]; map <vector<int>,int> mp; void dfs(int x,int y) { if(x>y) { if(tp==1) mp[vector <int> (buf+1,buf+N+1)]++; else { for(int i=1;i<=N;i++) f[i]=(cnt[i]>>1)-buf[i]; if(mp.find(vector <int> (f+1,f+N+1))!=mp.end()) ans+=mp[vector <int> (f+1,f+N+1)]; } return ; } buf[e[x].a]++; buf[e[x].b]++; if(buf[e[x].a]<=(cnt[e[x].a]>>1) && buf[e[x].b]<=(cnt[e[x].b]>>1)) dfs(x+1,y); buf[e[x].a]--; buf[e[x].b]--; dfs(x+1,y); } int main() { int ncase,i,j,z; scanf("%d",&ncase); while(ncase--) { scanf("%d%d",&N,&M); mp.clear(); memset(cnt,0,sizeof(cnt)); ans=0; for(i=1;i<=M;i++) { scanf("%d%d",&e[i].a,&e[i].b); cnt[e[i].a]++; cnt[e[i].b]++; } z=1; for(i=1;i<=N;i++) if(cnt[i]&1) z=0; if(!z) { printf("0\n"); continue ; } tp=1; dfs(1,M/2); tp=2; dfs(M/2+1,M); printf("%d\n",ans); } return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
原文地址:http://blog.csdn.net/w20810/article/details/47030255