1. 程式人生 > >HDU2141/POJ2785(二分查詢)

HDU2141/POJ2785(二分查詢)

HDU - 2141 Can you find it?

Give you three sequences of numbers A, B, C, then we give you a number X. Now you need to calculate if you can find the three numbers Ai, Bj, Ck, which satisfy the formula Ai+Bj+Ck = X. Input

There are many cases. Every data case is described as followed: In the first line there are three integers L, N, M, in the second line there are L integers represent the sequence A, in the third line there are N integers represent the sequences B, in the forth line there are M integers represent the sequence C. In the fifth line there is an integer S represents there are S integers X to be calculated. 1<=L, N, M<=500, 1<=S<=1000. all the integers are 32-integers. Output

For each case, firstly you have to print the case number as the form “Case d:”, then for the S queries, you calculate if the formula can be satisfied or not. If satisfied, you print “YES”, otherwise print “NO”. Sample Input

3 3 3  1 2 3  1 2 3  1 2 3  3  1  4  10

Sample Output

Case 1:  NO  YES  NO

問題求A+B+C=X是否存在

暴力求解求出三個陣列所有值的可能然後從中查詢是否有該值是不可行的,其時間複雜度為O(N^3)。

可以將等式進行變換為A+B=X-C,這樣需要在A+B所有的可能值中查詢X-C是否存在,將時間複雜度降為O(N^2),同時查詢我們使用二分查詢更快速。

#include<iostream>
#include<algorithm>
using namespace std;
int a[501], b[501],c[501],box[250005], s;     //box注意開大,避免陣列記憶體不夠
int l, n, m, k;
int binary_search(int x)                      //在box中二分查詢x
{
	int left = 1, right = k;
	while (left <= right)
	{
		int mid = (left + right) / 2;
		if (x > box[mid])
			left = mid + 1;
		else if (x < box[mid])
			right = mid - 1;
		else
			return 1;
	}
	return 0;
}
int main()
{
	int cases = 0;
	while (scanf("%d%d%d", &l, &n, &m) != EOF)
	{
		cases++;
		for (int i = 1; i <= l; i++)
			cin >> a[i];
		for (int i = 1; i <= l; i++)
			cin >> b[i];
	    k = 0;
		for (int i = 1; i <= l; i++)             //計算兩組數和的所有可能並排序
		{
			for (int j = 1; j <= n; j++)
			{
				box[++k] = a[i] + b[j];
			}
		}
		sort(box + 1, box + k+1);
		for (int i = 1; i <= l; i++)
			cin >> c[i];
		cin >> s;
		cout << "Case " << cases << ':' << endl;
		while (s--)
		{
			int x;
			cin >> x;
			int flag = 0;
			for (int i = 1; i <= m; i++)
			{
				if (binary_search(x - c[i]))      
				{
					flag = 1;
					break;
				}
			}
			if (flag)
				cout << "YES" << endl;
			else
				cout << "NO" << endl;
		}
	}
	return 0;
}

POJ2785  4 Values whose Sum is 0

Time Limit: 15000MS Memory Limit: 228000K
Total Submissions: 29423 Accepted: 8951
Case Time Limit: 5000MS

Description

The SUM problem can be formulated as follows: given four lists A, B, C, D of integer values, compute how many quadruplet (a, b, c, d ) ∈ A x B x C x D are such that a + b + c + d = 0 . In the following, we assume that all lists have the same size n .

Input

The first line of the input file contains the size of the lists n (this value can be as large as 4000). We then have n lines containing four integer values (with absolute value as large as 228 ) that belong respectively to A, B, C and D .

Output

For each input file, your program has to write the number quadruplets whose sum is zero.

Sample Input

6
-45 22 42 -16
-41 -27 56 30
-36 53 -37 77
-36 30 -75 -46
26 -38 -10 62
-32 -54 -6 45

Sample Output

5

Hint

Sample Explanation: Indeed, the sum of the five following quadruplets is zero: (-45, -27, 42, 30), (26, 30, -10, -46), (-32, 22, 56, -46),(-32, 30, -75, 77), (-32, -54, 56, 30).

暴力列舉明顯是不可能的,可以轉化為A+B=-(C+D),將A+B所有值放入一個數組中然後從陣列中二分查詢-(C+D)

所求所有可能的總數,故需要計算-(C+D)在陣列中是否存在,存在則有幾個,就用到了STL中的上下界二分查詢。

#include<iostream>
#include<algorithm>
using namespace std;
int a[4001], b[4001], c[4001], d[4001], box1[16000000], box2[16000000];
int n, k1 = 0, k2 = 0, ans = 0;            //box1中存放A+B,box2中存放C+D
int main()
{
	while (scanf("%d", &n) != EOF)
	{
		k1 = 0, k2 = 0, ans = 0;
		for (int i = 1; i <= n; i++)
			scanf("%d%d%d%d", &a[i], &b[i], &c[i], &d[i]);
		for (int i = 1; i <= n; i++)
			for (int j = 1; j <= n; j++)
				box1[++k1] = a[i] + b[j];
		sort(box1 + 1, box1 + k1 + 1);      //在box1中二分查詢,從小到大排序
		for (int i = 1; i <= n; i++)
			for (int j = 1; j <= n; j++)
				box2[++k2] = c[i] + d[j];
		for (int i = 1; i <= k2; i++)
		{
			int x1 = lower_bound(box1 + 1, box1 + k1+1, -box2[i]) - box1;//下界的角標序號
            int x2 = upper_bound(box1 + 1, box1 + k1+1, -box2[i]) - box1; //上界的角標序號
			if (x1 != x2)           //序號不相同則至少存在一個
				ans += (x2 - x1);
		}
		cout << ans << endl;
	}
	return 0;
}