您的位置:首页 > 其它

UVa 10125 Sumsets (中途相遇法)

2016-12-14 10:18 513 查看

UVa 10125 Sumsets

题目大意:

给一个整数集合S,找出最大的d,使得a+b+c=d,其中a,b,c,d是S中的不同元素.

(元素个数1<=n<=1000,元素大小-536870912<=x<=+536870911).

题目分析:

最直接的手段是直接枚举a,b,c,d,当然时间复杂度很高O(n^4).

但是若将四个数拆分成两两枚举,即先枚举a+b,储存起来,再枚举d-c,查找是否存在a+b==d-c.这样枚举的时间复杂度就降低了,这就是中途相遇法.

不过元素比较大,可以选择用哈希或者set实现,下面代码采用哈希.

需要注意一点的是,d-c查找到的a+b可能这四个数不一定互不相同.

代码:

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

const int hash_size=49999;
const int maxn=1000+10;

struct Node {
int val,i,j;//要考虑元素是否是选择了不同的,需要存下i和j
Node(){}
Node(int val,int i,int j):val(val),i(i),j(j){}
};

struct HashTable {//哈希表
Node to[maxn*maxn];//邻接表形式储存
int fir[hash_size],nxt[maxn*maxn],sz;
void clear() {
memset(fir,0,sizeof(fir));sz=0;
}
int hash(int val) {
return abs(val)%hash_size;
}
void insert(int val,int i,int j) {
int h=hash(val);
for(int k=fir[h];k;k=nxt[k])
if(to[k].val==val&&to[k].i==i&&to[k].j==j) return ;
nxt[++sz]=fir[h];fir[h]=sz;to[sz]=Node(val,i,j);
}
bool find(int val,int i,int j) {
int h=hash(val);
for(int k=fir[h];k;k=nxt[k])
if(to[k].val==val&&to[k].i!=i&&to[k].j!=j) return true;
return false;
}
}table;

int S[maxn],n;

int main()
{
while(scanf("%d",&n)==1&&n) {//中途相遇法
table.clear();
for(int i=0;i<n;i++) scanf("%d",&S[i]);
sort(S,S+n);//排序一下是为了便于后面找到答案就直接输出
for(int i=0;i<n;i++)
for(int j=i+1;j<n;j++)
table.insert(S[i]+S[j],i,j);
bool have=false;
for(int i=n-1;i>=0&&!have;i--)
for(int j=i-1;j>=0&&!have;j--)
if(table.find(S[i]-S[j],j,i))
printf("%d\n",S[i]),have=true;
if(!have) printf("no solution\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息