题目描述:
一共8个点,可能连很多条边,没有重边. 现在给这些边染两种颜色, 要求每一个点的边自己的黄边和红边个数相等. 问有多少种染色方法.
题解:
8个点,最多28条边.如果挑一个点和它相关的边不管,剩下的边都枚举,那么就是21条边.可以直接状态枚举21条边的情况.但是有100组数据. 发现每一个点度数一定是偶数,那么这满足偶数的图,除去一个点之后的边数一定小于21,因为一个点不能向外连7个边,只能连6条. 所以暴力加度数提前判断就好了.
重点:
首先去掉一个点枚举边.然后发现度数是偶数才能对.可以减少情况.
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <ctype.h>
#include <limits.h>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
#include <stack>
#include <set>
#include <bitset>
#define CLR(a) memset(a, 0, sizeof(a))
#define REP(i, a, b) for(int i = a;i < b;i++)
#define REP_D(i, a, b) for(int i = a;i <= b;i++)
typedef long long ll;
using namespace std;
const int maxn = 100 + 10;
struct Edge
{
int a, b;
};
int h1[9], l0[9];
vector<Edge> edge;
int key;
int G[maxn][maxn];
int n,m;
void solve()
{
int ans = 0;
CLR(G);
edge.clear();
REP_D(i, 1, m)
{
int a, b;
scanf("%d%d", &a, &b);
G[a][b] = 1;
G[b][a] = 1;
}
int temp = 0;
int tot_n;
for(int i = 1; i<=n; i++)
{
int t = 0;
for(int j = 1; j<=n; j++)
{
if(G[i][j])
{
t++;
}
}
if(t%2!=0)
{
printf("0\n");
return;
}
if(t > temp)
{
temp = t;
tot_n = i;
}
}
//n = tot_n;
for(int i = 1; i<=n; i++)
{
for(int j = i+1; j<=n; j++)
{
if(G[i][j])
{
if(i!=tot_n && j!=tot_n)
{
Edge t;
t.a = i;
t.b = j;
edge.push_back(t);
}
}
}
}
//n = tot_n;
int tot = edge.size();
key = (1<<tot);
for(int s = 0; s<key; s++)
{
CLR(h1);
CLR(l0);
for(int i = 0; i<tot; i++)
{
if( ((1<<i)&s) )
{
h1[edge[i].a]++;
h1[edge[i].b]++;
}
else
{
l0[edge[i].a]++;
l0[edge[i].b]++;
}
}
int flag = 1;
for(int i = 1; i<=n; i++)
{
if(i==tot_n)
continue;
if(G[tot_n][i])
{
if(h1[i]==l0[i] + 1)
{
l0[tot_n]++;
}
else if(h1[i]==l0[i]-1)
{
h1[tot_n]++;
}
else
{
flag = 0;
break;
}
}
else
{
if(h1[i]!=l0[i])
{
flag = 0;
break;
}
}
}
if(flag)
{
if(h1[tot_n]!=l0[tot_n])
{
flag = 0;
}
}
ans += flag;
}
printf("%d\n", ans);
}
int main()
{
// freopen("6Fin.txt", "r", stdin);
//freopen("6Fout.txt", "w", stdout);
int t;
scanf("%d", &t);
while(t--)
{
scanf("%d%d", &n, &m);
if(n==1 || m==0)
{
printf("1\n");
continue;
}
// if(n%2==1 && m == (n*(n-1)/2))
// {
// int t = (1<<m);
// printf("%d\n", t);
// }
solve();
}
return 0;
}