题目描述
有两个长度都为N的序列A和B,在A和B中各取一个数相加可以得到N2个和,求这N2个和中最小的N个。
输入
第一行一个正整数N(1 <= N <= 100000)。
第二行N个整数Ai,满足Ai <= Ai+1且Ai <= 109
第三行N个整数Bi,满足Bi <= Bi+1且Bi <= 109
输出
输出仅有一行,包含N个整数,从小到大输出这N个最小的和,相邻数字之间用空格隔开。
样例输入
3
2 6 6
1 4 8
样例输出
3 6 7
思路:可以用堆实现,也可以用优先队列实现,不过说到底实现的原理还是堆,因为优先队列的本质就是堆。
该题中最主要的就是利用了堆中的一个性质,堆顶元素最小或最大,此处使用小堆,即结点的值大于它的子节点。我们先把a中最小的数和b中所有的数加一遍,然后得到数组heap[n],此时再构建出一个小堆,然后把剩下的数相加后和堆顶作比较即可。
#include <iostream>
#include <algorithm>
using namespace std;
int heap[100010], n;
void downAdjust(int low, int high){
int i = low, j = i * 2;
while(j <= high){
if(heap[j+1] > heap[j] && j+1 <= high) j = j + 1;
if(heap[i] < heap[j]){
swap(heap[i], heap[j]);
i = j;
j = i * 2;
}else{
break;
}
}
}
void createHeap(){
for(int i=n/2; i>=1; i--)
downAdjust(i, n);
}
int main()
{
int a[100010], b[100010];
cin >>n;
for(int i=0; i<n; i++) scanf("%d", &a[i]);
for(int i=0; i<n; i++) scanf("%d", &b[i]);
//把a中最小的数和b里所有的数加一遍
for(int i=0; i<n; i++) heap[i+1] = a[0] + b[i];
createHeap(); //构建堆
//剩下的数相加
for(int i=1; i<n; i++){
for(int j=0; j<n; j++){
int sum = a[i] + b [j];
if(sum < heap[1]){ //如果加数小于堆顶元素
heap[1] = sum; //交换值并且向下调整
downAdjust(1, n);
}else{
break; //剪枝
}
}
}
sort(heap+1, heap+1+n); //可以再写一个堆排序算法也可以直接sort
for(int i=0; i<n; i++) printf("%s%d", i==0?"":" ", heap[i+1]);
return 0;
}