2 3 3 1 2 2 3 3 1 4 4 1 2 2 3 3 4 4 1
0 2
题意:
给一个图,不存在重边。
任意两个人(结点)有线上或者线下的关系,但是每个人线上和线下关系的朋友必须一样多。
求有几种方案。
=====等效于对图的边黑白染色。每个点的黑色边和白色边要一样。
分析:
特判如果存在边的度数为奇数的,直接输出0.
只有八个人。实际上最复杂的情况是每个人的边数都是6条。那么枚举每个人,把他们的边染色。选出一半的边染成黑色。
分析最复杂的情况C(3,6)*C(3,6)*C(2,4)*C(2,4)*C(1,2)*C(1,2)
为什么后面的C边数少了呢?因为之前枚举点的时候已经处理了这些边。所以后面就不用处理了。
剪枝:如果一个点的黑色边数 > 入度的一半,结束这次搜索
#include<iostream> #include<cstring> #include<algorithm> #include<cstdio> #include<vector> using namespace std; vector <int >head[10]; int online[10]; int in[10]; int n; int dfs(int u); int dfs2(int u,int p,int num){ if(num == 0){ dfs(u+1); return 0; } for(;p < head[u].size() && num+p <= head[u].size(); p++){ int v = head[u][p]; online[v]++; if(online[v] * 2 <= in[v]){ dfs2(u,p+1,num-1); } online[v]--; } return 0; } int ans; int dfs(int u){ if(u == n+1){ ans++; return 0; } int need = in[u] / 2 - online[u]; dfs2(u,0,need); } int main(){ int out[10]; int t; scanf("%d",&t); while(t--){ int m; scanf("%d%d",&n,&m); for(int i = 1;i <= n; i++) head[i].clear(); memset(in,0,sizeof(in)); memset(out,0,sizeof(out)); int u,v; for(int i = 0;i < m; i++){ scanf("%d%d",&u,&v); if(u > v) swap(u,v); head[u].push_back(v); in[u]++,in[v]++; } int flag = 1; for(int i = 1;i <= n; i++){ if(in[i] % 2 == 1) flag = 0; } if(flag){ memset(online,0,sizeof(online)); ans = 0; dfs(1); printf("%d\n",ans); } else printf("0\n"); } return 0; }