Sumsets(UVA10125)整数集合
备课的时候发现了这道题,对于初识哈希来说并不算一道很简单的题。在查阅林厚从老师的示例代码与往届OI选手的博客后,大致理解了本题的思路。
相关标签: Hash
Description
给定一个整数集合S,求一个最大的d,满足a+b+c=d,其中a,b,c,d∈S
Input
多组数据,每组数据包括:
- 第一行一个整数n,代表元素个数
- 下面n行每行一个整数,代表集合元素
输入结束的标志为n=0。
Output
对于每组数据,输出:
- 一行,如果有解,输出一个整数,代表最大的d;否则输出no solution
Sample Input
Sample Output
Hint
n≤1000,保证输入的集合元素互不相同。
集合中的元素∈[-536 870 912,536 870 911]。
解题思路
a,b,c,d。共四个数,如果想采用最简单枚举法,复杂度将来到O(n4)。题目数据来说,一定会超时。
考虑题目数据量约在103,O(n2)的做法差不多能够接受。考虑做以下方法:找到两组对,使得 d-c = a+b 。若等式满足,更新d的最大值即可。
如何快速找到、定位两组值?考虑使用Hash方法。即先用n2的时间(两重循环)枚举a+b,并将其打包成对,以a+b的值为key,存入Hash数组中。
再用n2的时间(两重循环)枚举d-c,并将b-c的值作为键,在Hash数组中查找是否存在。如果能找到key相同的node点,则找到了一组满足 d-c = a+b的值。(注意检查a b c d 四个数不重复)
此时,维护ans更新为更大的d值即可。如果找不到此组合,则输出no solution
通过代码
#include<iostream> #include<cstdio> #include<cstring> #define inf -536870912 using namespace std; const int maxM=1000007; const int maxN=1010; int n; int hash1[3*maxM], a[maxN]; //hash table -- source data struct node{ int key,x1,x2,next; }data[maxN * maxN]; //hash node int main(){ while(scanf("%d",&n) && n){ for(int i=1;i<=n;i++) scanf("%d",a+i); memset(hash1,0,sizeof(hash1)); memset(data,0,sizeof(data)); int k=0; for(int i=1;i<=n;i++){ for(int j=i+1;j<=n;j++){ data[++k].key=a[i]+a[j]; data[k].x1=i; data[k].x2=j; int x=data[k].key % maxM; if(x<0) x=-x; while(hash1[x]>0) { x=x+1; x=x % maxM; } hash1[x]=k; } } int ans=inf; for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++) if(j!=i){ int key=a[i]-a[j]; int x=key % maxM; if(x<0) x=-x; int p=x; int flag=0; while(hash1[p]>0 && !flag){ int p1=hash1[p]; if (data[p1].key==key && data[p1].x1!=i && data[p1].x2!=i && data[p1].x1!=j && data[p1].x2!=j) flag=1; else { p=p+1; p = p%maxM; }; } if(hash1[p]>0 && a[i]>ans) ans=a[i]; } } if(ans!=inf) cout<<ans<<endl; else cout<<"No Solution"<<endl; } }