Problem C - Sumsets
Given S, a set of integers, find the largest d such that a + b + c = d where a, b, c, and d are distinct elements of S.Input
Several S, each consisting of a line containing an integer 1 <= n <= 1000 indicating the number of elements in S, followed by the elements of S, one per line. Each element of S is a distinct integer between -536870912 and +536870911 inclusive. The last line of input contains 0.Output
For each S, a single line containing d, or a single line containing "no solution".Sample Input
5 2 3 5 7 12 5 2 16 64 256 1024 0
Output for Sample Input
12 no solution
题意:
给你一个集合,要求从里面找出4个不同数字满足a+b+c=d
分析:
直接枚举a,b,c,d肯定是要超时的,所以就要用到一些技巧。
有一种算法叫做中途相遇法。对与这道题来说可以把等式重新划分成 a+b=d-c,首先预处理出所有a+b的值。然后从大到小枚举d,和c,验证是否存在a+b满足要求。这样复杂度就从n^4降到了n^2。 当然还要验证a,b,c,d不相等,所以哈希表中的节点要还应保存a,b的信息。
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <iostream>
#define INF 0x7fffffff
using namespace std;
typedef long long LL;
const int HASHSIZE = 1e6 + 7;
const int N = 1e3 + 10;
struct node
{
int x,y,sum;
}v[N*N];
int head[HASHSIZE],next[N*N];
int tot;
int a[N];
int Hash(int x)
{
return (x&0x7fffffff)%HASHSIZE;
}
void Insert(int x)
{
int h=Hash(v[x].sum);
next[x]=head[h];
head[h]=x;
}
int Find(int d,int c, int sum)
{
int h=Hash(sum);
for(int i=head[h];i!=-1;i=next[i])
{
if(v[i].x != c
&& v[i].x != d
&& v[i].y != c
&& v[i].y != d
&& v[i].sum == sum)
return 1;
}
return 0;
}
int main()
{
int n;
while(scanf("%d",&n)&&n)
{
memset(head,-1,sizeof(head));
tot=0;
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
}
sort(a,a+n);
for(int i=0;i<n;i++)
{
for(int j=i+1;j<n;j++)
{
v[tot].x=i;
v[tot].y=j;
v[tot].sum=a[i]+a[j];
Insert(tot);
tot++;
}
}
int ok=0,ans;
for(int i=n-1;i>=0;i--) // d
{
for(int j=0;j<n;j++) if(i!=j) // c
{
int sum=a[i]-a[j];
if(Find(i,j,sum))
{
ans=a[i];
ok=1;
break;
}
}
if(ok) break;
}
if(ok) printf("%d\n",ans);
else printf("no solution\n");
}
return 0;
}