【codevs1425】最小的N个和,如何像煞笔一样地写堆

来源:互联网 发布:html中js用函数传值 编辑:程序博客网 时间:2024/04/30 22:04

1245 最小的N个和
时间限制: 1 s
空间限制: 128000 KB
题目等级 : 钻石 Diamond
题解
题目描述 Description
有两个长度为 N 的序列 A 和 B,在 A 和 B 中各任取一个数可以得到 N^2 个和,求这N^2 个和中最小的 N个。

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

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

样例输入 Sample Input
5

1 3 2 4 5
6 3 4 1 7

样例输出 Sample Output
2 3 4 4 5

数据范围及提示 Data Size & Hint
【数据规模】 对于 100%的数据,满足 1≤N≤100000。
写在前面:我以后再也不碰没学过的数据结构题目了(论自学的必要性,不要觉得自己什么都会,不看就去写!(/▽╲))
——————————————————————————————————————————————
解题思路:刚开始我拿到这道题发现要用堆写,然后我就崩溃了,因为我不会!我不会!我不会!后来自己看了一点基本操作,又做了几道非常基础的练习才拿过来再写,后来发现不是我想象的那么容易,刚开始我是想到了取a[i]b[j]必定要取a[i-1]b[j]和a[i][j-1],但是我发现数据范围太大,然后就不知道怎么去存储和调用,然后只能去问问Yveh大爷,后来他给我发了个解题思路,然后写出来了……
先对ab排序,然后
这里写图片描述
就像这样,我们发现让b(或a)的第一个元素去和所有的a(b)中的元素相加并入堆(边入边维护,这里用小根堆),然后进行n次循环,吧堆顶元素弹出,然后堆顶元素更新为原堆顶元素同一行右边的数字,再次维护即可,这样做是一定可以找到前n个最小和的
代码:

#include<cstdio>#include<iostream>#include<algorithm> #include<cstring>using namespace std;int n,len,t,x,a[100001],b[100001],answer[100001];struct os{    int num,sum,aa;//sum存该元素b中的位置,aa是a数组的位置,num存和}teap[100001];int fix(){    int fa=1;    while (fa*2<=len-1)    {        int kk=fa*2;        if (kk+1<=len-1&&teap[kk].num>teap[kk+1].num) kk++;        if (teap[fa].num>teap[kk].num) {swap(teap[fa],teap[kk]);fa=kk;}        else break;    }    return t;}void put(){        for (int i=1;i<=n;i++)    {        len++;        teap[len].num=a[i]+b[1];        teap[len].sum=1;        teap[len].aa=i;        fix();    }}main() {    scanf("%d",&n);    for (int i=1;i<=n;i++) scanf("%d",&a[i]);    for (int i=1;i<=n;i++) scanf("%d",&b[i]);    sort(a+1,a+n+1);    sort(b+1,b+n+1);    memset(teap,127,sizeof(teap));    put();    int k=0;    for (int i=1;i<=n;i++)    {        k++;        answer[k]=teap[1].num;        teap[1].num=a[teap[1].aa]+b[teap[1].sum+1];        teap[1].sum++;        fix();      }     for (int i=1;i<=k;i++) printf("%d ",answer[i]);}
0 0
原创粉丝点击