UVA 10125 - Sumsets(POJ 2549) hash

67 篇文章 1 订阅
58 篇文章 0 订阅

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1066

http://poj.org/problem?id=2549

题目大意:

给定一个整数几何S,找出一个最大的d,使得a+b+c=d,其中a,b,c,d是S中不同的元素。

S的个数最大为1000。

思路:

直接暴力枚举a,b,c,d必挂。

上面的式子移向得:a+b=d-c。我们先预处理所有的和,并且插入Hash表。

然后枚举d和c,看是否在Hash表中是否存在。

若存在且不同,则更新d。

类似的题目还有:

HDU 1496 Equations hash HDU上排名第一!

POJ 2785 4 Values whose Sum is 0 Hash!

HDU 1407 测试你是否和LTC水平一样高 枚举、二分、hash

PS:

一开始这里的

if(data[i].sum!=sum || data[i].a==a ||data[i].a==b ||data[i].b==a ||data[i].b==b )

data[i].b==b 然后WA到哭了。。呜呜呜呜,后来发现想撞死。。来去吃点好吃的安慰一下我受伤的心灵。哈哈


0.072S,让暴力枚举的见鬼去吧~

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=1024;
const int mod=1<<18;
int x[MAXN],head[mod],len;
struct data
{
	int a,b,sum;
	int next;
}data[MAXN*MAXN];

inline int gethash(int x)
{
	if(x<0) x=-x;   //变为正的
	return (x) & (mod-1);
}
void insert(int a,int b,int sum)
{
	int cur=gethash(sum);
	for(int i=head[cur];i!=-1;i=data[i].next)
	{
		if(data[i].sum==sum && data[i].a==a && data[i].b==b)
			return;
	}
	data[len].a=a;
	data[len].b=b;
	data[len].sum=sum;
	data[len].next=head[cur];
	head[cur]=len++;
}
bool search(int a,int b,int sum)
{
	int cur=gethash(sum);
	for(int i=head[cur];i!=-1;i=data[i].next)
	{
		if(data[i].sum!=sum ||	data[i].a==a ||	data[i].a==b ||	data[i].b==a ||	data[i].b==b )
			continue;
		return true;
	}
	return false;
}
int main()
{
	int n;
	while(~scanf("%d",&n),n)
	{
		len=0;
		memset(head,-1,sizeof(head));

		for(int i=0;i<n;i++)
			scanf("%d",&x[i]);

		for(int i=0;i<n;i++)
			for(int j=i+1;j<n;j++)	
				insert(i,j,x[i]+x[j]);
				//	insert(x[i],x[j],x[i]+x[j]);这样是错的,应该用下标来判断是否同一个。
				//因为元素可能相同。

		bool ok=false;
		int ans=-999999999;
		for(int i=0;i<n;i++)
		{		
			for(int j=0;j<n;j++)
			{
				if(i==j) continue;
				if(search(i,j,x[i]-x[j]))
				{
					ok=true;
					ans=max(ans,x[i]);
					break;
				}
			}
		}
		if(ok) printf("%d\n",ans);
		else puts("no solution");
	}
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值