Sequence 【二叉堆】

题目描述

给定M个长度为n的序列,从每个序列中任取一个数求和,可以构成NM个和,求其中最小的N个和。N<=2000,M<=100。

输入

第一行是整数T,它显示测试用例的数量,然后是T个测试用例。每种情况的第一行都包含两个整数m,n。以下m行分别表示m序列。序列中没有整数大于10000。

输出

对于每个测试用例,按升序打印具有最小n个和的行,并用空格隔开。

样例输入

1
2 3
1 2 3
2 2 3

样例输出

3 3 4

解题思路:

1.我们可以先从简单情况考虑:当M=2时,就是从2个序列中任取一个数相加构成的N2个和中求出前N小的和。设这两个序列为A和B,将其分别排序
2.可以发现最小和一定为A[1]+B[1],次小和就是A[1]+B[2]和A[2]+A[1]中取小值,即min(A[1]+B[2],A[2]+B[1]).若次小和为A[2]+B[1],那第三小的和就是A[1]+B[2],A[2]+B[2],A[3]+A[1]中最小的。总结一下,当确定A[i]+B[j]为第t小和时,A[i+1]+B[j]与A[i]+B[j+1]就是第t+1小和的备选方案
3.注意:A[1]+B[2]与A[2]+B[1]都可以产生A[2]+B[2]这个答案,会发生重复现象。可以这样规定:如果把j+1产生新的答案,那么以后只能增加j,不能增加i.也就是说,从A[1]+B[1]到任何A[i]+B[j]必须先向后移动i,再向后移动j,这样就可以使答案不重不漏,我们可以定义一个bool变量flag实现这一功能。
4.先建立一个小根堆,每个节点存储(i,j,flag)这几个参数,flag表示上一次移动的是否是j. 起初:(1,1,false) 然后取出堆顶(i,j,flag),然后把(i,j+1,true)插入堆,如果flag为false再把(i+1,j,false)也插入堆。 重复上一步N次,每次取出堆顶节点的权值A[i]+B[j]一起构成前N小和。时间复杂度为O(NlogN),整个算法时间复杂度为O(MNlogN)

代码:

#include<bits/stdc++.h>
#define N 10005
using namespace std;
struct node
{
   
    int i,j,v,flag;
    friend bool operator<(node a,node b) 
    {
   
        
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值