题意:给你一些数,两两的话可以组成很多和,在给你一些其他的数,找前边算出来的和中最接近后边这些数的和。
方法:求和,排序去重,二分查找。
注意: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排序,程序大改后没注意。
原文:http://blog.csdn.net/u013545222/article/details/18970413