uva - 10487 - Closest Sums(二分查找)

题意:给你一些数,两两的话可以组成很多和,在给你一些其他的数,找前边算出来的和中最接近后边这些数的和。

方法:求和,排序去重,二分查找。

注意: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排序,程序大改后没注意。


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值