【数据结构•堆】序列和的前n小元素(堆排序)

题目描述

问题:序列和的前n小元素
给出两个长度为n的有序表A和B, 在A和B中各任取一个, 可以得到 n^2 个和. 求这些和最小的n个。

输入输出格式

输入格式:

输入数据共三行。
  第一行,一个整数值n ( n <= 10^4 )。
  第二,第三行,各有n个从小到大排好序的整数,每个整数间有一个空格间隔。(每个整数均小于2^30)

输出格式:

输出数据一行,这些和最小的n个数,从小到大输出,每个整数之间一个空格间隔。

输入输出样例

输入样例#1:

3
2 6 6
1 4 8

输出样例#1:

3 6 7

思路

我刚看到这题的时候还以为是到水题,不就是给 n 2 n^2 n2个数排个序然后输出吗?结果花两分钟写完代码然后直接TLE
然后听了一下老师的评讲,发现确实是一道水题
思路大概就是:
1.建一个大根堆(优先队列)来维护a数组b数组的和
!!!是大根堆不是小根堆!!!不要看它是从小到大排序就建小根堆因为大根堆的堆顶是最大的,相当于一个守门员,所有数想要进堆就必须经过它。我们可以借助这个堆顶来筛选所有数字。
2.双重循环暴力枚举a数组b数组的和,但!!!这里可以剪枝!!!由于输入的是两个有序表,所以只要有一个加出来的和比大根堆的堆顶大,那么后面加出来的和会比大根堆的堆顶更大,是不可能入得了堆的。所以直接break就行啦
3.将比堆顶小的a数组b数组的和放入堆中
4.这时我们可以得到一个从大到小的队列(大顶堆),最后倒过来输出一下就AC

如果没看懂就看看代码和注释吧:

AC代码

#include
using namespace std;
int n,t,a[100001],ans,b[100001],c[100001];
map<int,int> p;
priority_queue <int,vector<int>,less<int> > q;//从大到小 
//priority_queue ,greater > q1;//从小到大 
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){//输入 
		cin>>a[i];
	}
	for(int i=1;i<=n;i++){//先将a[1]+b[1...n]放入队列 
		cin>>b[i];
		q.push(a[1]+b[i]);
	}
	for(int i=2;i<=n;i++){//枚举 
		for(int j=1;j<=n;j++){
			if(a[i]+b[j]>q.top()) break;
			//由于b是一个有序表,所以如果当前这个都大了那么后面的会更大 ,所以可以直接break 
			q.pop();//弹出最大的 
			q.push(a[i]+b[j]);//放入新的数 
		}
	}
	//这时得到了一个大顶堆,我不知道怎样倒过来,所以用了最笨的方法,如果有更好的方法欢迎评论区讨论哦
	int i=0;
	while(!q.empty()){//倒过来
		i++;
		c[i]=q.top();
		q.pop();
	}
	for(int j=i;j>=1;j--) cout<<c[j]<<" ";//输出
	return 0;
}

这题这样就过啦,记得三连支持一下哦QAQ

你可能感兴趣的:(编程万能专栏(什么都有),排序,数据结构,算法,c++)