hdu5305 Friends(dfs+map/hash)

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

题意:给定N个人和M条朋友关系,是朋友关系的两个人之间有两种联系方式online和offline。使每一个人的online的数量和offline的数量相等,求方案数。

分析:因为M<=28,暴力枚举的话2^28非常大,会超时。能够考虑把全部的状态平分成两半,即枚举前面M/2条关系,暴力求出前面的2^(M/2)种状态,然后枚举后面M/2条关系,暴力求出后面2^(M/2)种状态,再枚举后面一半的状态,对于每一种状态直接在前面一半的状态里面找出满足条件的就可以。找状态用dfs比二进制枚举要快,查询的话map比hash方便。。。

代码:

#include <iostream>
#include <vector>
#include <cstdio>
#include <cstring>
#include <map>
using namespace std;
int N,M,cnt[20],buf[20],f[20],ans,tp;
struct node
{
	int a,b;
}e[200];
map <vector<int>,int> mp;
void dfs(int x,int y)
{
	if(x>y)
	{
		if(tp==1)
			mp[vector <int> (buf+1,buf+N+1)]++;
		else
		{
			for(int i=1;i<=N;i++)
				f[i]=(cnt[i]>>1)-buf[i];
			if(mp.find(vector <int> (f+1,f+N+1))!=mp.end())
				ans+=mp[vector <int> (f+1,f+N+1)];
		}
		return ;
	}
	buf[e[x].a]++;
	buf[e[x].b]++;
	if(buf[e[x].a]<=(cnt[e[x].a]>>1) && buf[e[x].b]<=(cnt[e[x].b]>>1))
		dfs(x+1,y);
	buf[e[x].a]--;
	buf[e[x].b]--;
	
	dfs(x+1,y);
}
int main()
{
	int ncase,i,j,z;
	scanf("%d",&ncase);
	while(ncase--)
	{
		scanf("%d%d",&N,&M);
		mp.clear();
		memset(cnt,0,sizeof(cnt));
		ans=0;
		for(i=1;i<=M;i++)
		{
			scanf("%d%d",&e[i].a,&e[i].b);
			cnt[e[i].a]++;
			cnt[e[i].b]++;
		}
		z=1;
		for(i=1;i<=N;i++)
			if(cnt[i]&1)
				z=0;
		if(!z)
		{
			printf("0
");
			continue ;
		}
		tp=1;
		dfs(1,M/2);
		tp=2;
		dfs(M/2+1,M);
		printf("%d
",ans);
	}
	return 0;
}

另一种更简单的方法,直接dfs然后剪一下枝。假设一个人有x个朋友,那么暴力搜的过程中出现online的个数>x/2或者offline的个数>x/2就不满足条件也就不用搜了。

#include <iostream>
#include <cstdio>
using namespace std;

int on[10],off[10],d[10],N,M,ans,x[30],y[30];
void dfs(int cur)
{
	if(cur>M)
	{
		for(int i=1;i<=N;i++)
			if(on[i]!=off[i])
				return ;
		++ans;
		return ;
	}
	int u=x[cur],v=y[cur];
	if(on[u]<d[u]/2 && on[v]<d[v]/2)
	{
		on[u]++;on[v]++;
		dfs(cur+1);
		on[u]--;on[v]--;
	}
	if(off[u]<d[u]/2 && off[v]<d[v]/2)
	{
		off[u]++;off[v]++;
		dfs(cur+1);
		off[u]--;off[v]--;
	}
}
int main()
{
	int ncase,i,j,k;
	scanf("%d",&ncase);
	while(ncase--)
	{
		scanf("%d%d",&N,&M);
		memset(d,0,sizeof(d));
		for(i=1;i<=M;i++)
		{
			scanf("%d%d",&x[i],&y[i]);
			d[x[i]]++;
			d[y[i]]++;
		}
		ans=0;
		dfs(1);
		printf("%d
",ans);
	}
	return 0;
}


原文地址:https://www.cnblogs.com/claireyuancy/p/6946462.html