Codeup——616 | 问题 B: 序列合并

题目描述

有两个长度都为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;
}
上一篇:nlfs 20034 #12440「NOIP2021模拟赛0923北大附」入教


下一篇:随机化数组