UVa 10125 Sumsets (中途相遇法)

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值