题意:给出若干两人的组合,可任意确定两人为线上或线下朋友,使得每人的线上线下朋友数量相同。问有几种方法?
算法:DFS
问题:需要剪枝,不然超时。
思路: 储存每个人的总关系数,如果是奇数显然不行;深搜时每步判断每个人的当前的某个关系数是否小于总关系数的一半。
代码:ac
#include<bits/stdc++.h>
using namespace std;
int t;
int n, m;
int con[30][2];/*朋友对应关系*/
int on[10], off[10];/*每个人线上线下朋友数*/
int ti[10];
int cnt;
/*测试:int test = 0;*/
void dfs(int k);
int check(int s1[], int s2[],int p)/*判断是否朋友数相等*/
{
for (int i = 1; i <= p; i++)
if (s1[i] != s2[i])return 0;
return 1;
}
int main()
{
scanf("%d", &t);
while (t--) {
cnt = 0;
memset(on, 0, sizeof(on));
memset(off, 0, sizeof(off));
memset(ti, 0, sizeof(ti));
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; i++) {
scanf("%d%d", &con[i][0], &con[i][1]);
ti[con[i][0]]++;
ti[con[i][1]]++;
}
int flag = 1;
for (int i = 1; i <= n; i++) {
if (ti[i] % 2 == 1) {
printf("0\n");
flag = 0;
break;
}
}
if (flag) {
dfs(1);
printf("%d\n", cnt);
}
}
return 0;
}
void dfs(int k)/*k为已用关系数+1*/
{
if (k == m + 1) {
/*测试程序*/
/*printf("%d\n", ++test);
for (int i = 1; i <= n; i++) {
printf("on:%d,off:%d\n", on[i], off[i]);
}
printf("%d\n", check(on, off, n));
printf("\n\n");*/
if (check(on, off, n))cnt++;
return;
}
/*剪枝*/
if (on[con[k][0]] < ti[con[k][0]] / 2 && on[con[k][1]] < ti[con[k][1]] / 2) {
on[con[k][0]]++;/*对应朋友数加1*/
on[con[k][1]]++;
dfs(k + 1);
on[con[k][0]]--;/*如果on不行,退回上一步选off*/
on[con[k][1]]--;
}
if (off[con[k][0]] < ti[con[k][0]] / 2 && off[con[k][1]] < ti[con[k][1]] / 2) {
off[con[k][0]]++;
off[con[k][1]]++;
dfs(k + 1);
off[con[k][0]]--;
off[con[k][1]]--;
}
return;
}