[Wikioi 1245][二叉堆]最小的N个和

题目描述 Description

有两个长度为 N 的序列 A 和 B,在 A 和 B 中各任取一个数可以得到 N^2 个和,求这N^2 个和中最小的 N个。

第一行输入一个正整数N;第二行N个整数Ai 且Ai≤10^9;第三行N个整数Bi,
且Bi≤10^9

输出仅一行,包含 n 个整数,从小到大输出这 N个最小的和,相邻数字之间用
空格隔开。

5

1 3 2 4 5 
6 3 4 1 7

2 3 4 4 5

【数据规模】 对于 100%的数据,满足 1≤N≤100000。

题目思路:

本题是《训练指南》第189面的题的变种(原题比此题更难),原理上来说其实不难,但是由于本题范围太大,单纯使用数组必定会MLE,因此需要借助二叉堆,二叉堆的元素用结构体定义为node,为了节约空间,node结构体中不必包含a值,只需包含sum和b的值,a的值可以通过sum和b求出,但在使用时同样要注意不能MLE,怎么办呢?先把数组a[],b[]降序排序,从0~n对a[i]+b[0]求和入堆,再从堆顶开始,对堆中每个元素的b值进行判断,只要b<n,就表明某个元素的b值为b+1是存在的,又由于二叉堆是最大化堆,数组也是降序的,a[i]+b[j+1]>a[i]+b[j]必然成立,将元素{sum,b[j]}出堆,将{sum',b[j+1]}入堆,这样就能节约空间,不至于MLE了,本题充分考察了对二叉堆特性的应用,是一道很经典的题目。

#include <stdio.h>
#include <queue>
#include <algorithm>
#define MAXN 100005
using namespace std;
struct node
{
	int sum,b;
	bool operator < (node a) const
	{
		return sum>a.sum;
	}
}heap[MAXN*2];
priority_queue<node> q;
int cmp(int x,int y)
{
	return x<y;
}
int main()
{
	int n,i,j,in,a[MAXN],b[MAXN];
	scanf("%d",&n);
	for(i=0;i<n;i++)
	{
		scanf("%d",&a[i]);
	}
	for(i=0;i<n;i++)
	{
		scanf("%d",&b[i]);
	}
	sort(a,a+n,cmp);
	sort(b,b+n,cmp);
	for(i=0;i<n;i++)
		q.push((node) {a[i] + b[0], 0});
	for(i=0;i<n;i++)
	{
		node buf=q.top(); //将堆顶的元素buf(sum,b)取出
		q.pop();//出堆
		printf("%d ",buf.sum);
		if(buf.b<n) //如果元素buf的b<n的话,表明还可以得到元素x={sum+1,b+1},将它压入堆中
			q.push((node){buf.sum-b[buf.b]+b[buf.b+1],buf.b+1});
	}
	printf("\n");
	return 0;
}


你可能感兴趣的:(struct,二叉堆)