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

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值