1. 程式人生 > >POJ 二分查詢 快速找到和為零的四個數

POJ 二分查詢 快速找到和為零的四個數

問題描述

定義求和問題如下:給定4組整數A,B,C,D,找到有多少四元組(a,b,c,d)∈A×B×C×D,滿足條件a+b+c+d=0。此問題中,假設A,B,C,D具有相同的大小n。

輸入資料

輸入包含多組測試資料。每組測試資料的第一行包含一個整數n,表示A,B,C,D的元素個數(n<=4000)。接下來n行每行4個整數,分別屬於A,B,C,D,每個整數的大小在-228~228之間。

輸出要求

對於每組測試資料,輸出滿足條件的四元組的個數。

輸入樣例

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

輸出樣例

5

解題思路

將問題轉化為兩組整數的問題。首先枚舉出a、b兩組所有可能的和sum1,以及c、d兩組所有可能的和sum2,將這兩組和看成新的組數,然後根據給定兩組和為0,對於sum1中每一個數sum1[i],判斷-sum1[i]是否在sum2中。即問題轉化為查詢問題,可以使用二分查詢加快查詢速度。首先對sum1,sum2元素排序,從小到大列舉每一個元素sum1[i],使用二分查詢判斷-sum1[i]是否在陣列中,然後計算出現的次數。陣列中可能會出現相同的元素,所以採用變形的二分法,在有重複元素的陣列中返回小於或等於目標元素的最大元素,若返回元素等於目標元素,則沿著陣列計數該元素出現的次數。採用左右都是閉區間

的區間規則。

程式碼

#include<iostream>
#include<algorithm>
using namespace std;
int Sum1[10000006],Sum2[10000006];
int a[4001],b[4001],c[4001],d[4001];
int t=0;
int FindCount(int target)
{
    //二分查詢
    int l=0,h=t-1,num=0;
    while(l<h)
    {
        int mid=l+(h-l)/2;
        if(target<=Sum2[mid]) //查詢重複元素
        {
h=mid; } else { l=mid+1; } } while(Sum2[l]==target&&l<t) //計算重複出現的次數 { num++; l++; } return num; } int main() { int n; cin>>n; for(int i=0;i<n;i++) { cin>>a[i]>>b[i]>>c[i]>>d[i]; } for(int i=0;i<n;i++) { for(int j=0;j<n;j++) { Sum1[t]=a[i]+b[j]; Sum2[t]=c[i]+d[j]; t++; } } sort(Sum1,Sum1+t); sort(Sum2,Sum2+t); int num=0; for(int i=t-1;i>=0;i--) { num+=FindCount(-Sum1[i]); } cout<<num<<endl; return 0; }