HDU 5305 Friends (DFS,穷举+剪枝)

题意:给定n个人,m对朋友关系,如果对于每个人,只能刚好选择其所有朋友中的一半的人进行聊天(只是我和我的朋友,不是我的朋友和我的朋友),那么有多少种情况?只要一个选择不同,视为不同情况。

思路:比如我在14个朋友中选择了7个跟我聊天,那么另外7人已经完全与我没干系,而和我聊天的7个朋友,也已经和我聊天了,即我们配对了,共7对,他所选择的那一半的人中也必须有我。

  其实只考虑所给的m条边就行了。如果是奇数对关系,必定有人是奇数个朋友,那么也就0种情况。如果是偶数条边,还得判断每个人是否都是偶数个朋友,若不是也是0种。

  满足了情况之后再对m个关系选取其中的m/2条即可。但是所选的关系也必须是满足要求的,那么对于所选的m/2条关系进行判断即可知道是否满足要求,穷举所有可能进行判断。DFS就可以了,每条边要么选,要么不选。但是必须剪枝才能过。

 1 #include <bits/stdc++.h>
 2 #define LL long long
 3 #define pii pair<int,int>
 4 #define INF 0x7f7f7f7f
 5 using namespace std;
 6 const int N=10;
 7 int n, m, s[65], e[65], num, times[N], du[N];
 8 int DFS(int x)  //x是第几条边
 9 {
10     if( num*2>=m )      //已经够一半了,判断是否满足要求
11     {
12         for(int i=1; i<=n; i++)    if( 2*du[i]!= times[i] ) return 0;   //每个人的度有一半即可。
13         return 1;
14     }
15
16     int ans=0;
17     if(  du[ s[x] ]*2<times[ s[x] ] && du[ e[x] ]*2 <times[e[x]] )  //剪枝:这条边两个端点都已经满度,就不能再选了。
18     {
19         du[s[x]]++,du[e[x]]++;
20         num++;          //所选边的数量
21         ans+=DFS(x+1);
22         du[s[x]]--,du[e[x]]--;
23         num--;
24     }
25
26     if( m/2-num < m-x  )     //还没有决定是否选的边数必须不小于m的一半
27         ans+=DFS(x+1);
28     return ans;
29 }
30
31 int cal(int n )
32 {
33     //先检查是否满足奇数度的要求
34     if(m&1)     return 0;
35     for(int i=1; i<=n; i++)    if( times[i]&1 )   return 0;
36
37     num=0;
38     memset(du,0,sizeof(du));
39     return DFS(0);
40 }
41
42 int main()
43 {
44     //freopen("e://input.txt", "r", stdin);
45     int t;
46     cin>>t;
47     while(t--)
48     {
49         memset(times, 0, sizeof(times));
50         scanf( "%d%d",&n,&m );
51         for(int i=0; i<m; i++)
52         {
53             scanf("%d%d",&s[i],&e[i]);
54             times[s[i] ]++; //记录朋友个数
55             times[e[i] ]++;
56         }
57         printf("%d\n",cal(n));
58     }
59     return 0;
60 }

AC代码

时间: 2025-01-07 12:51:09

HDU 5305 Friends (DFS,穷举+剪枝)的相关文章

HDU 5305 Friends (DFS)

Friends Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 163    Accepted Submission(s): 61 Problem Description There are n people and m pairs of friends. For every pair of friends, they can choo

HDU 5339 Untitled (递归穷举)

题意:给定一个序列,要求从这个序列中挑出k个数字,使得n%a1%a2%a3....=0(顺序随你意).求k的最小值. 思路:排个序,从大的数开始模起,这是因为小的模完还能模大的么? 每个元素可以选,也可以不选,两种情况.递归穷举每个可能性,O(2n). 1 //#include <bits/stdc++.h> 2 #include <cstdio> 3 #include <cstring> 4 #include <map> 5 #include <al

hdu 1044(bfs+dfs+剪枝)

Collect More Jewels Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 6739    Accepted Submission(s): 1564 Problem Description It is written in the Book of The Lady: After the Creation, the cruel

HDU 1017 A Mathematical Curiosity (输出格式,穷举)

#include<stdio.h> int main() { int N; int n,m; int a,b; int cas; scanf("%d",&N); while(N--) { cas=1;//必须在这儿初始化cas,坑 while(scanf("%d%d",&n,&m),n||m) { int count=0; for(a = 1; a < n; a++)//穷举法 { for(b = a + 1; b <

HDU 1017 A Mathematical Curiosity【看懂题意+穷举法】

//2014.10.17    01:19 //题意: //先输入一个数N,然后分块输入,每块输入每次2个数,n,m,直到n,m同一时候为零时 //结束,当a和b满足题目要求时那么这对a和b就是一组 //注意: //每一块的输出中间有一个回车 A Mathematical Curiosity Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s)

HDU 1407 测试你是否和LTC水平一样高【穷举法】

/* 解题思路:暴力求解 难点详解:注意每个数都没有超过num 关键点:穷举法 解题人:lingnichong 解题时间:2014-08-28 10:56:15 解题体会:第一次使用goto语句,感觉goto语句还是有点实用的价值的 */ 测试你是否和LTC水平一样高 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 12878    A

HDU - 1175 连连看 DFS (记录方向)

连连看HDU - 1175 "连连看"相信很多人都玩过.没玩过也没关系,下面我给大家介绍一下游戏规则:在一个棋盘中,放了很多的棋子.如果某两个相同的棋子,可以通过一条线连起来(这条线不能经过其它棋子),而且线的转折次数不超过两次,那么这两个棋子就可以在棋盘上消去.不好意思,由于我以前没有玩过连连看,咨询了同学的意见,连线不能从外面绕过去的,但事实上这是错的.现在已经酿成大祸,就只能将错就错了,连线不能从外围绕过. 玩家鼠标先后点击两块棋子,试图将他们消去,然后游戏的后台判断这两个方格能

穷举递归和回溯算法终结篇

穷举递归和回溯算法 在一般的递归函数中,如二分查找.反转文件等,在每个决策点只需要调用一个递归(比如在二分查找,在每个节点我们只需要选择递归左子树或者右子树),在这样的递归调用中,递归调用形成了一个线性结构,而算法的性能取决于调用函数的栈深度.比如对于反转文件,调用栈的深度等于文件的大小:再比如二分查找,递归深度为O(nlogn),这两类递归调用都非常高效. 现在考虑子集问题或者全排列问题,在每一个决策点我们不在只是选择一个分支进行递归调用,而是要尝试所有的分支进行递归调用.在每一个决策点有多种

hdu 1518 Square(深搜+剪枝)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1518 题目大意:根据题目所给的几条边,来判断是否能构成正方形,一个很好的深搜应用,注意剪枝,以防超时! 1 #include <iostream> 2 #include <cstdio> 3 #include<algorithm> 4 #include <cstring> 5 using namespace std; 6 int ap[30],visit[30]