备课的时候发现了这道题,对于初识哈希来说并不算一道很简单的题。在查阅林厚从老师的示例代码与往届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;
}
}