二分查找POJ-2785 4 Values whose Sum is 0
题目链接:POJ-2785
题目大意:输入四列数 代表集合a,b,c,d 问ai+bi+ci+di相加等于0的组合有多少种
解题思路:将ab集合每种组合对应的和储存 cd也是一样 然后查找cd集合中是否有ab集合元素的复数 ab集合和cd集合的大小最大可达4000*4000 直接遍历查找会超时 所以用二分查找法(注意在二分查找的时候 找到了需要的数组不要直接返回 总数加一 还要在找到的地方向前向后判断是否还有其他组合的和与查询的相同)
第一个wa在忘记了多样例输入 第二个wa在向前向后查找的时候 数组的索引出现了越界 在测试1 0 0 0 0 这组数据的时候输出了特别大的数字
代码块:
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int a[4001];
int b[4001];
int c[4001];
int d[4001];
int ab[4001*4001];
int cd[4001*4001];
int index = 0;
int search(int x);
int main(){
int n;
while(cin>>n){
int size = 0;
for(int i=0;i<n;i++){
scanf("%d %d %d %d",&a[i],&b[i],&c[i],&d[i]);
}
for(int i = 0;i<n;i++){
for(int j = 0;j<n;j++){
ab[index] = a[i]+b[j];
cd[index] = c[i]+d[j];
index++;
}
}
sort(cd,cd+index);
for(int i = 0; i < index;i++){
size += search(-ab[i]);
}
cout<<size<<endl;
index = 0;
}
return 0;
}
int search(int x){
int sum = 0;
int left = 0;
int right = index - 1;
while(left <= right){
int mid = (left + right)/2;
if(x == cd[mid]){
sum++;
int inx = mid-1;
//找到之后向前找看有没有相同的
while(true){
if(x == cd[inx] && inx>=0){//注意索引不能越界
sum++;
inx--;
}else{
break;
}
}
//向后找看有没有相同的
inx = mid+1;
while(true){
if(x == cd[inx] && inx <= index-1){
sum++;
inx++;
}else{
break;
}
}
return sum;
}else if(x < cd[mid]){
right = mid - 1;
} else{
left = mid + 1;
}
}
return sum;
}