题意:给你一些数,两两的话可以组成很多和,在给你一些其他的数,找前边算出来的和中最接近后边这些数的和。
方法:求和,排序去重,二分查找。
注意:1、要先求和再去重,如果边求和,再在和里查找重复就不插入的会TLE,本来数据很多,再套一层循环的话代价非常大。2、二分查找不太会,但是先查找,如果正好有和某一个和相等直接返回。如果没有也就是while循环完了以后,检查low和high所指的数和ques[a]的绝对值大小,取小的那个。注意low和high有可能数组越界,如果越界就把他们定在边界上,见代码。
#include <iostream>
#include <iomanip>
#include <string>
#include <cstring>
#include <cstdio>
#include <queue>
#include <stack>
#include <algorithm>
#include <cmath>
using namespace std;
#define MAX (1000+10)
int m, n, num[MAX], ques[25], temp_sum[MAX*MAX], sum[MAX*MAX], p;
void Input()
{
int i = 0, j = 0;
for (i = 0; i < m; i++)
cin >> num[i];
cin >> n;
for (i = 0; i < n; i++)
cin >> ques[i];
}
void Cal_Sum()
{
int i = 0, j = 0, k = 0;
for (i = 0; i < m; i++)
{
for (j = i+1; j < m; j++)
{
temp_sum[p++] = num[i] + num[j];
}
}
}
void Sum()
{
int i = 0, j = 1;
sum[0] = temp_sum[0];
for (i = 1; i < p; i++)
if (temp_sum[i-1] != temp_sum[i])
sum[j++] = temp_sum[i];
p = j;
}
int BinSearch(int a)
{
int i = 0;
int low = 0, mid = 0, high = p-1, d = 2147482647;
while (high >= low)
{
mid = (high+low)/2;
if (sum[mid] == ques[a])
return sum[mid];
else if (ques[a] > sum[mid])
low = mid+1;
else
high = mid-1;
}
if (high < 0) high = 0;
if (low > p-1) low = p-1;
int x = sum[low], y = sum[high];
if (abs(x - ques[a]) > abs(y - ques[a])) return y;
else return x;
}
int main()
{
#ifdef Local
freopen("a.in", "r", stdin);
freopen("a.out", "w", stdout);
#endif
int i = 0, t = 0;;
while (cin >> m && m)
{
memset(num, 0, sizeof(num));
memset(ques, 0, sizeof(ques));
memset(sum, 0, sizeof(sum));
memset(temp_sum, 0, sizeof(temp_sum));
p = 0;
Input();
Cal_Sum();
sort(temp_sum, temp_sum+p);
Sum();
cout << "Case " << ++t << ":" << endl;
for (i = 0; i < n; i++)
{
cout << "Closest sum to " << ques[i] << " is " << BinSearch(i) << "." << endl;
}
}
}
1、宏定义的问题,MAX = 1000+10,但是写了个MAX*MAX ,RE了,因为没打括号。应该 MAX(1000+10)。
2、循环问题。
3、sort应该给temp_sum排序,程序大改后没注意。