Problem B: 序列合并

Description

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

Input

第一行一个正整数N(1 <= N <= 100000)。
第二行N个整数Ai,满足Ai <= Ai+1且Ai <= 109
第三行N个整数Bi,满足Bi <= Bi+1且Bi <= 109

Output

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

Sample Input

3
2 6 6
1 4 8

Sample Output

3 6 7

HINT

建议用最小堆实现。

 

题目链接:序列合并

参考链接:最小的N个和(优先队列)

最终AC代码如下:

#include<bits/stdc++.h>
using namespace std;
const int MAX=1e5+2;
struct Node{
    int index, sum;
    bool operator < (const Node &t) const{
        return sum > t.sum; //优先队列表示按sum的大小排列 
    }
};
int main(){
    int i, n, a[MAX], b[MAX];
    Node temp, now;
    priority_queue<Node> q;
    while(cin >> n){
        for(i=0; i<n; i++) scanf("%d", &a[i]);
        for(i=0; i<n; i++){
            scanf("%d", &b[i]);
            temp.index = 0;
            temp.sum = b[i] + a[temp.index];  //index表示a[]中的第几个数字 
            q.push(temp);
        }
        for(i=0; i<n; i++){
            now = q.top();
            q.pop();
            if(now.index+1 < n){
                temp.index = now.index + 1;
                temp.sum = now.sum - a[now.index] + a[temp.index];
                q.push(temp);
            }
            printf("%d%c", now.sum, i==n-1?'\n':' ');
        }
    }  
    return 0;
}

总结:一开始看见提示,用最小堆做,但是没想到具体的思路~自认为本题的难点在于,虽然两组数据都是分别单调不减的,但是要求和最小(分别从两个序列中取数,每个数可以重复利用)的前N个数,于是就有很多不确定性了。如果数据量不是很大的情况,也许可以暴力,但是此题显然不行。

参考别人的思路后,发现可以用优先队列做(平时优先队列用得少,真的没想起这思路)。自己对这种思路的理解大致如下:

首先,取a[]数组中的最小元素,也就是a[0],分别加上b[i](0<=i<n),并放入优先队列中。那么可以确定,此时优先队列队首的元素,也即a[0]+b[0]的值就是最小的,可以输出,并将a[1]+b[0]输入优先队列,依次类推,直到输出了n个数为止。

上述过程,逻辑看似简单,但是要注意几点:

1、优先队列存放的元素是结构体变量。定义结构体的目的,结构体内sum变量存放两个数之和,index记录a[]的下标,从而为后面每次更新sum埋伏笔。

2、由于优先队列存放的元素是结构体变量,因此需要自定义比较的容器~然而这种定义方式着实不易理解,暂且先记住。

3、入队前对index的范围的判断,在此题可以省略(试了一下,没啥影响)。

posted @ 2020-04-16 12:04  已是夕阳,不如放下  阅读(324)  评论(0编辑  收藏  举报