您的位置:首页 > 其它

HDU 5305 Friends(DFS + 剪枝)

2017-04-20 13:28 281 查看
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: