hdu 4277 USACO ORZ

USACO ORZ

Time Limit: 5000/1500 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 5470    Accepted Submission(s): 1802


Problem Description
Like everyone, cows enjoy variety. Their current fancy is new shapes for pastures. The old rectangular shapes are out of favor; new geometries are the favorite.
I. M. Hei, the lead cow pasture architect, is in charge of creating a triangular pasture surrounded by nice white fence rails. She is supplied with N fence segments and must arrange them into a triangular pasture. Ms. Hei must use all the rails to create three sides of non-zero length. Calculating the number of different kinds of pastures, she can build that enclosed with all fence segments. 
Two pastures look different if at least one side of both pastures has different lengths, and each pasture should not be degeneration.
 

Input
The first line is an integer T(T<=15) indicating the number of test cases.
The first line of each test case contains an integer N. (1 <= N <= 15)
The next line contains N integers li indicating the length of each fence segment. (1 <= li <= 10000)
 

Output
For each test case, output one integer indicating the number of different pastures.
 

Sample Input
1 3 2 3 4
 

Sample Output
1
 

Source
 

Recommend
liuyiding   |   We have carefully selected several similar problems for you:  4276 4274 4268 4272 4267 

我好菜啊。。。

一道挺水的题帮别人调了很久。。。

最后还是求助师兄。。

主要还是hash部分

我hash好菜啊。。。

注意根据三条边算出的hash值相同就认为三条边的方案相同

所以投进add函数里的hash值不能先取余mod

我这里用的是unsigned long long 自然溢出

这是我帮别人调的代码(其实很大部分都是我改过来的。。。)

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int t,n,a[16],tot=0,l1,l2,summ;
const int mod=903457;
int last[mod+10];
struct node
{
	int pre;
	unsigned long long too;
	void clear()
	{
		pre=0,too=0;
	}
}e[2000005];
void add(unsigned long long val)
{
	int x=val%mod;
	for(int i=last[x];i;i=e[i].pre) if(e[i].too==val) return;
	e[++tot].too=val,e[tot].pre=last[x],last[x]=tot;
}	
bool check(unsigned long long val)
{
	int i=last[val%mod];
	while(i&&e[i].too!=val) i=e[i].pre;
	return i>0;
}
void dfs(int x,int l1,int l2)
{
	if(x>n+1)	return;
	if(l1>0&&l2>0&&l1<=l2&&l2<=summ-l1-l2)
		if((l1+l2)>(summ-l1-l2)&&(summ-l2)>l2&&(summ-l1)>l1)
		{	
		    unsigned long long ans=l1;
		    ans=ans*1000000007+l2;
		    ans=ans*1000000007+summ-l1-l2;
			if(check(ans)==0)		add(ans);
		}
	dfs(x+1,l1,l2);
	dfs(x+1,l1,l2+a[x]);
	dfs(x+1,l1+a[x],l2);
	return;
}
int main()
{
	scanf("%d",&t);
	for(int i=1;i<=t;i++)
	{
		memset(last,0,sizeof(last));
		for(int j=1;j<=tot;j++)	e[j].clear();
		tot=0;
		scanf("%d",&n);
		summ=0;
		for(int j=1;j<=n;j++)		
		{
			scanf("%d",&a[j]);
			summ+=a[j];
		}	
		if(n<3) printf("0\n");
		else 
		{
			dfs(1,0,0);
			printf("%d\n",tot);
		}	
	}
	return 0;
}

下面是我自己写的代码:

我用的是枚举子集的子集

注意枚举子集的子集的复杂度是3^n的

所以要先2^n处理出每个状态的边值

大大优化了程序的时间效率

由于dfs常数大

所以我的程序比上面快了三倍左右

#include<cstdio>
#include<cstring>
const int mod=903457,K=1000000007;
int tin[(1<<15)+100];
struct node
{
	unsigned long long val;
	int next;
	void clear()
	{
		val=0;next=0;
	}
}e[2000000];
int a[16];
int cnt=0;
int first[mod+5];
inline void add(unsigned long long val)
{
	int x=val%mod;
	for(int i=first[x];i;i=e[i].next)
	if(e[i].val==val)return;
	e[++cnt].val=val,e[cnt].next=first[x],first[x]=cnt;
}
inline bool check(unsigned long long val)
{
	int i ;
	for(i=first[val%mod];i;i=e[i].next)	if(e[i].val==val)	break;
	return i>0;
}
int main()
{
	int n;int sum=0;
	int t;
	scanf("%d",&t);
	while(t--)
	{
		memset(first,0,sizeof(first));
		for(int i=1;i<=cnt;i++)	e[i].clear();
		cnt=0;sum=0;
		scanf("%d",&n);
		for(int i=1;i<=n;i++)		scanf("%d",&a[i]),sum+=a[i];
		int top=(1<<n)-1;
		for(int i=0;i<=top;i++)	
		{
			int j=i,cnt=1;int su=0;
			while(j)
			{
				if(j&1)	su+=a[cnt];
				j=j>>1;
				cnt++;
			}
			tin[i]=su;
		}
		for(int sta=1;sta<=top;sta++)
		{
			for(int s=sta;s;s=(s-1)&sta)
			{
				int l1=tin[s],l2=tin[sta^s],l3=sum-l1-l2;
				if(l2==0||l3==0||l1==0)	continue;	
				if((l1+l2)>l3&&(l1+l3)>l2&&l2+l3>l1&&l1<=l2&&l2<=l3)
				{
					unsigned long long val=l1;
					val=val*K+l2;
					val=val*K+l3;
					if(check(val)==0)	add(val);
				}
			}
		}
		printf("%d\n",cnt);
	}
	return 0;
}

posted @ 2017-08-09 22:05  Brian551  阅读(170)  评论(0编辑  收藏  举报