[DFS] 多校联合第二场 F题 Friends

时间:2021-04-30 00:23:48

Friends

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 0 Accepted Submission(s): 0

Problem Description
There are n people and m pairs of friends. For every pair of friends, they can choose to become online friends (communicating using online applications) or offline friends (mostly using face-to-face communication). However, everyone in these n people wants to have the same number of online and offline friends (i.e. If one person has x onine friends, he or she must have x offline friends too, but different people can have different number of online or offline friends). Please determine how many ways there are to satisfy their requirements.

Input
The first line of the input is a single integer T (T=100), indicating the number of testcases.

For each testcase, the first line contains two integers n (1≤n≤8) and m (0≤m≤n(n−1)2), indicating the number of people and the number of pairs of friends, respectively. Each of the next m lines contains two numbers x and y, which mean x and y are friends. It is guaranteed that x≠y and every friend relationship will appear at most once.

Output
For each testcase, print one number indicating the answer.

Sample Input
2
3 3
1 2
2 3
3 1
4 4
1 2
2 3
3 4
4 1

Sample Output
0
2

由于总点数很少,考虑暴力搜索,但是总的边数最多有可能是8*7/2 = 28,所以不能直接枚举每条边的状态。

注意到以下几点可以优化:
1、当num[i]为奇数时,一定不满足分配的方法。
2、当总边数等于0时,只有一种分配的方法。
3、如果总分配的边数量为奇数那么一定不满足分配的方法。

将这几种可能的情况剪掉以后,就可以在给定的时间复杂度内过了。

这个暴力dfs个人觉得非常难写,主要是因为判断各个符合对应状态的条件很困难,平时自己写这一类的搜索题非常少,所以能力上还差一些。用num[]存储每条边需要计算的数量,sum为总共需要计算的边数,将所有的可达情况分配到边中去,并且恰好可以完全分配时,就是可以完成的方案。

#include <stdio.h>
#include<iostream>
#include <string.h>
#include <algorithm>
using namespace std;
typedef long long ll;

int n,m;
pair<int,int> e[64];
int num[10];
int sum;

//m 边数 sum 还剩下的边有多少条 k:当前搜索的位置
int dfs(int k){
if(k==m){ //当前搜索的位置如果刚好剩下的边都没有了那就好了
if(sum==0) return 1;
return 0;
}
//还剩下的边若填满接下来的位置还有剩余的话
//就不用继续往下搜索了,肯定不满足该条件
if(4*(m-k) < sum) return 0;

int ans=0;
ans+=dfs(k+1);
//cout<<ans<<endl;
int u=e[k].first,v=e[k].second;
if(num[u]>=2 && num[v]>=2){
num[u]-=2;
num[v]-=2;
sum-=4;
ans+=dfs(k+1);
num[u]+=2;
num[v]+=2;
sum+=4;
}
return ans;
}

int solve(){
if(m==0) return 1;
if(m%2) return 0;
for(int i=1; i<=n; i++)
if(num[i]%2) return 0;
return dfs(0);
}

int main(){
//freopen("in.txt","r",stdin);
int T;
scanf("%d",&T);
while(T--){
memset(num,0,sizeof num);
sum=0;
scanf("%d%d",&n,&m);
for(int i=0; i<m; i++){
int u,v;
scanf("%d%d",&u,&v);
e[i].first=min(u,v);
e[i].second=max(u,v);
num[u]++;
num[v]++;
sum+=2;
}
sort(e,e+m);

printf("%d\n",solve());
}
return 0;
}