题目描述:
有两个长度都为N的序列A和B,在A和B中各取一个数相加可以得到 N 2 N^2 N2个和,求这 N 2 N^2 N2个和中最小的N个。
输入:
第一行一个正整数N(
1
≤
N
≤
100000
1 \le N \le 100000
1≤N≤100000)。
第二行N个整数
A
i
A_i
Ai,满足
A
i
≤
A
i
+
1
且
A
i
≤
1
0
9
A_i \le A_i+1且A_i \le 10^9
Ai≤Ai+1且Ai≤109
第三行N个整数
B
i
B_i
Bi,满足
B
i
≤
B
i
+
1
且
B
i
≤
1
0
9
B_i \le B_i+1且B_i \le 10^9
Bi≤Bi+1且Bi≤109
输出:
输出仅有一行,包含N个整数,从小到大输出这N个最小的和,相邻数字之间用空格隔开。
样例输入:
3
2 6 6
1 4 8
样例输出:
3 6 7
提示:
建议用最小堆实现。
实现代码:
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 100000 + 10;
int a[maxn];
int b[maxn];
int heap[maxn];
int n = 0;
// 向下调整大顶堆
void down_adjust(int low, int high) {
int i = low, j = i * 2;
while(j <= high) {
if(j + 1 <= high && heap[j] < heap[j + 1]) {
j = j + 1;
}
if(heap[i] < heap[j]) {
swap(heap[i], heap[j]);
i = j;
j = i * 2;
} else {
break;
}
}
}
// 建堆
void create_heap() {
for(int i = n / 2; i >= 1; i--) {
down_adjust(i, n);
}
}
int main() {
while(scanf("%d", &n) != EOF) {
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
for(int i = 1; i <= n; i++) {
scanf("%d", &b[i]);
}
// 先将a的第一个元素与b中所有元素分别相加放入堆中
for(int i = 1; i <= n; i++) {
heap[i] = a[1] + b[i];
}
create_heap();
//遍历其他相加和,将其与堆顶比较,如果比堆顶小,则替换堆顶,并进行向下调整堆
for(int i = 2; i <= n; i++) {
for(int j = 1; j <= n; j++) {
int add_num = a[i] + b[j];
if(add_num < heap[1]) {
heap[1] = add_num;
down_adjust(1, n);
} else {
break;
}
}
}
//排序
for(int i = n; i > 1; i--) {
swap(heap[i], heap[1]);
down_adjust(1, i - 1);
}
for(int i = 1; i <= n; i++) {
printf("%d", heap[i]);
if(i <= n - 1) {
printf(" ");
} else {
printf("\n");
}
}
}
return 0;
}