题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5305
题意:有n个人,其中有m对朋友关系,每队关系中两个人可以是网上交流或面对面交流,通过分配给所有关系以居停交流方式,若果分配完毕后每个人的网上交流朋友都与面对面交流的朋友一样多,那么这个分配是有效的,问共有多少种有效分配。
解析:容易想到DFS,但直接做时间复杂度为2^28,这里进行剪枝,即先计算出每个人的关系数量,在DFS时每个人的任何种类交流方式的朋友数量都不能超过个人关系数量的1半(因为如果某种关系数量超过了一半,一定形不成有效分配)。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxN=30;
int n,m,num[maxN],ans;//num[i]即i的关系数量
int x[maxN],y[maxN]; //x[i]和y[i]是第i个关系的起点和终点
int on[maxN],off[maxN];//on[i]和off[i]是i的两种关系的数量
void dfs(int step)
{
if(step==m+1)
{
bool f=true;
for(int i=1;i<=n;i++)
if(on[i]!=off[i]) {f=false;break;}
if(f==true) ans++;
return;
}
if(on[x[step]]<num[x[step]]/2&&on[y[step]]<num[y[step]]/2)
{
on[x[step]]++;
on[y[step]]++;
dfs(step+1);
on[x[step]]--;
on[y[step]]--;
}
if(off[x[step]]<num[x[step]]/2&&off[y[step]]<num[y[step]]/2)
{
off[x[step]]++;
off[y[step]]++;
dfs(step+1);
off[x[step]]--;
off[y[step]]--;
}
return;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
ans=0;
memset(num,0,sizeof(num));
memset(on,0,sizeof(on));
memset(off,0,sizeof(off));
for(int i=1;i<=m;i++)
{
scanf("%d%d",&x[i],&y[i]);
num[x[i]]++;
num[y[i]]++;
}
bool f=true;
for(int i=1;i<=n;i++)
{
if(num[i]&1) {f=false;break;}
}
if(f==false)
{
printf("0\n");
}
else
{
dfs(1);
printf("%d\n",ans);
}
}
return 0;
}