HDU 5305 Friends(DFS + 剪枝)

来源:互联网 发布:mysql 5.0 32位下载 编辑:程序博客网 时间:2024/05/29 14:50

http://acm.hdu.edu.cn/showproblem.php?pid=5305

题目大意就是,有m对朋友,每个人可以有线上和线下朋友,对于每个人,要求线上和线下朋友数目相同。

做法:我们直接把朋友关系保存,当成边,然后DFS枚举每一条边两种情况,两人互为网友或者是线下的朋友。但是这样最高的复杂度达到了2^28,而且T等于100,这样显然是不足以在时限内解决问题的。此时想尽办法剪枝。

剪枝的地方有:1,如果有人的朋友是奇数个,则肯定不存在合理的情况,直接输出0

2,DFS的时候,枚举第x条边,但是这条边的某个端点s,他的线上朋友数已经是他自己的朋友数的一半,那么不可以把它放入线上情况递归下去。同样的,如果线下的朋友数达到了他自己朋友数的一半,也不可放入线下的情况递归下去。

代码如下:

#include<bits/stdc++.h>using namespace std;vector < pair<int,int> > fri;int n, cnt, fact[15], online[15], spot[15], top[15];void dfs(int x){if(x == fri.size()){cnt++;return;}if(online[fri[x].first] < top[fri[x].first] && online[fri[x].second] < top[fri[x].second]){online[fri[x].first]++;online[fri[x].second]++;dfs(x+1);online[fri[x].first]--;online[fri[x].second]--;}if(fact[fri[x].first] < top[fri[x].first] && fact[fri[x].second] < top[fri[x].second]){fact[fri[x].first]++;fact[fri[x].second]++;dfs(x+1);fact[fri[x].first]--;fact[fri[x].second]--;}}int main(){int T,m,x,y;cin >> T;while(T--){memset(fact,0,sizeof(fact));memset(online,0,sizeof(online));memset(spot,0,sizeof(spot));fri.clear();cnt = 0;scanf("%d%d", &n, &m);if(n == 1){printf("1\n");continue;}if(m == 0){printf("1\n");continue;}while(m--){scanf("%d%d", &x, &y);fri.push_back(make_pair(x,y));spot[x]++;spot[y]++;}bool flag = 1;for(int i = 1; i <= n; i++){if(spot[i] % 2 == 1)flag = 0;top[i] = spot[i] / 2;}if(flag == 0){printf("0\n");continue;}online[fri[0].first]++;online[fri[0].second]++;dfs(1);online[fri[0].first]--;online[fri[0].second]--;fact[fri[0].first]++;fact[fri[0].second]++;dfs(1);fact[fri[0].first]--;fact[fri[0].second]--;cout << cnt << endl;}return 0; } 


0 0