题目链接:http://wikioi.com/problem/1245/
算法与思路:K路归并 + 堆(优先队列),K路归并具体请参考刘汝佳《算法竞赛入门经典训练指南》P189;
题目要求从两个长度为n的数列中各取出一数相加,可得到n*n个和,输出这些和升序的前n项;
由于数据太大,不能通过先求和再排序的方式来求解,这个时候就要用到堆了;
首先将a,b两数组排序,然后将a[i] + b[1]压入堆中,设每次出堆的元素为sum = a[a] + b[b],
则将a[a] + b[b + 1]入堆,这样可以保证前n个出堆的元素为最小的n项;在实现的时候,
可以不用保存b数组的下标,通过sum - b[b] + b[b + 1]来替换a[a] + b[b + 1]来节省空间。
#include<cstdio>
#include<queue>
#include<algorithm>
using namespace std;
const int N = 100005;
struct node
{
int sum;
int b;
bool operator < (node a) const
{
return sum > a.sum;
}
}heap[N * 2];
priority_queue<node>q;
int cmp(int x, int y)
{
return x < y;
}
int main()
{
int n, a[N], b[N], i;
scanf("%d", &n);
for(i = 1; i <= n; i++)
scanf("%d", &a[i]);
for(i = 1; i <= n; i++)
scanf("%d", &b[i]);
sort(a + 1, a + n + 1, cmp);
sort(b + 1, b + n + 1, cmp);
for(i = 1; i <= n; i++)
q.push((node){a[i] + b[1], 1});
for(i = 1; i <= n; i++)
{
node buf = q.top();
q.pop();
printf("%d ", buf.sum);
if(buf.b <= n)
q.push((node){buf.sum - b[buf.b] + b[buf.b + 1], buf.b + 1});
}
return 0;
}