UVA10487Closest Sums(二分)

来源:互联网 发布:lvs调度算法 编辑:程序博客网 时间:2024/05/16 10:49

Given is a set of integers and then a sequence of queries. A query gives you a number and asks to find a sum of two distinct numbers from the set, which is closest to the query number.
Input
Input contains multiple cases.
Each case starts with an integer n (1 < n ≤ 1000), which indicates, how many numbers are in the
set of integer. Next n lines contain n numbers. Of course there is only one number in a single line. The next line contains a positive integer m giving the number of queries, 0 < m < 25. The next m lines contain an integer of the query, one per line.
Input is terminated by a case whose n = 0. Surely, this case needs no processing. Output
Output should be organized as in the sample below. For each query output one line giving the query value and the closest sum in the format as in the sample. Inputs will be such that no ties will occur.
Sample Input
5
3
12
17
33
34
3
1
51
30
3
1
2
3
3
1
2
3
3
1
2
3
3
4
5
6
0
Sample Output
Case 1:
Closest sum to 1 is 15.
Closest sum to 51 is 51.
Closest sum to 30 is 29.
Case 2:
Closest sum to 1 is 3.
Closest sum to 2 is 3.
Closest sum to 3 is 3.
Case 3:
Closest sum to 4 is 4.
Closest sum to 5 is 5.
Closest sum to 6 is 5.

题目大意:
给你N个数,其中任意两个数相加的和sum 尽量靠近m[i],找到这个最接近sum。 n<=1e3,m<=25;
朴素想法:
算出所有n^2种可能,对于每一个询问遍历查找。时间复杂度n^2+ m*n*n*K(很多组数据)。
优化:
1.先排序,查找的时候用二分。n^2+n^2lgn^2+m*log2(n^2)*K;
2.还有一种更加优化的方法。不用算出n^2种结果。
先将n个数排序。对于每个询问 枚举一个数i,再用二分去查找另一个j。时间复杂度m*n*log2(n)*k;

实现:
窝用的是第三种优化方法。实现上需要注意的是,
其一,在二分查找j的时候,如何剔除已经枚举了的数i。有可能最后二分出来的结果是i+i。。然而这是不允许的,于是需要判断if(i==j)。
其二,有可能我们二分出来的结果并不是最接近的那个数。因为二分只能控制找出的那个数《=我们想要的那个数,,而可能比二分出来的结果大一点点的数加起来更加接近目标。于是窝们需要对左or右的数做一个判断取优。

//  Created by ZYD in 2015.//  Copyright (c) 2015 ZYD. All rights reserved.//#include <cstdio>#include <cstdlib>#include <iostream>#include <algorithm>#include <cstring>#include <climits>#include <string>#include <vector>#include <cmath>#include <stack>#include <queue>#include <set>#include <map>using namespace std;#define maxn 1000000#define ll long long#define mk make_pair#define pb push_back#define mem(array) memset(array,0,sizeof(array))typedef pair<int,int> P;int tot=0,n,a[2000],m,b,t,anss,ans,l,r,mid,x,bz;int main(){    freopen("in.txt","r",stdin);    while(~scanf("%d",&n) && n)    {        mem(a);        printf("Case %d:\n",++tot);        for(int i=1;i<=n;i++)            cin>>a[i];        sort(a+1,a+n+1);        cin>>m;        for(int i=1;i<=m;i++)        {            cin>>x;anss=maxn;            for(int j=1;j<=n;j++)            {                l=1;r=n;                bz=x-a[j];                while(l<r)                {                    mid=(l+r) /2;                    if(a[mid]>=bz) r=mid;                    else l=mid+1;                }                r=l+1;                if(l==j) l--;                if(r==j) r++;                if(l) ans=a[l]+a[j];                else ans=a[r]+a[j];                if(r<=n && fabs(a[r]+a[j]-x)<fabs(ans-x)) ans=a[r]+a[j];                if((l-1)!=j && (l-1)>0 && fabs(a[l-1]+a[j]-x)<fabs(ans-x)) ans=a[l-1]+a[j];//if(tot==4) cout<<ans<<endl;                if(fabs(ans-x)<fabs(anss-x)) anss=ans;            }            printf("Closest sum to %d is %d.\n",x,anss);        }    }    return 0;}
0 0