题目:已知n个数a[1..n],还有另一个数M,在前n个数中找到差值最小的两个数使得他们的和是M。
分析:数学。排序,找M/2。然后向两边分别扩展即可。
设a[s]是第一个大于M/2的数字,
如果M是偶数,并且存在至少两个M/2,则a[s-1]、a[s-2]一定是M/2;
否则a[s-1] <= M/2 ,a[s] > M,从这两点向两边扩展即可(l = s-1,r = s):
若a[l]+a[r] > M,l 向左移动(l --)
若a[l]+a[r] < M,r 向右移动(r ++)
若 a[l]+a[r] = M,则就是解,这是a[l]的a[r]差最小(因为,差值和r与l的插值正相关)。
说明:╮(╯▽╰)╭l --写成了r ++RE好几次。
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstdio>
using namespace std;
int data[10012];
int bs( int r, int key )
{
int mid,l = 0;
while ( l < r ) {
mid = l+(r-l)/2;
if ( data[mid] <= key )
l = mid+1;
else r = mid;
}
return r;
}
int main()
{
int n,sum;
while ( ~scanf("%d",&n) ) {
for ( int i = 0 ; i < n ; ++ i )
scanf("%d",&data[i]);
data[n] = 1000002;
scanf("%d",&sum);
sort( data, data+n );
int s = bs( n, sum/2 );//找到第一个大于sum/2的值
if ( s >= 2 && data[s-1]+data[s-2] == sum )
printf("Peter should buy books whose prices are %d and %d.\n\n",data[s-2],data[s-1]);
else {
int l = s-1,r = s;
while ( l >= 0 && r < n ) {
if ( data[l]+data[r] == sum ) {
printf("Peter should buy books whose prices are %d and %d.\n\n",data[l],data[r]);
break;
}else if ( data[l]+data[r] < sum )
r ++;
else l --;
}
}
}
return 0;
}