0x10基本数据结构(0x17 二叉堆)例题2:序列

题意

题目链接

【题意】
给定m个序列,每个包含n个非负整数。
现在我们可以从每个序列中选择一个数字以形成具有m个整数的序列。
很明显,我们一共可以得到n^m个这种序列, 然后我们可以计算每个序列中的数字之和,并得到n^m个值。
现在请你求出这些序列和之中最小的n个值。 

 【输入格式】
第一行输入一个整数T,代表输入中包含测试用例的数量。
接下来输入T组测试用例。
对于每组测试用例,第一行输入两个整数m和n。
接下在m行输入m个整数序列,数列中的整数均不超过10000。 

 【输出格式】
对于每组测试用例,均以递增顺序输出最小的n个序列和,数值之间用空格隔开。
每组输出占一行。 

 【数据范围】
0<m≤1000
0<n≤2000 

  【输入样例】
1
2 3
1 2 3
2 2 3 

  【输出样例】
3 3 4 

题解

这道题目,我们一开始看是蒙的。

但是看了YXC巨佬的视频不就会了吗。

这道题目,我们不能直接算\(m\)个序列的\(m\)小值。

我们发现其实我们可以算出第\(1\)和第\(2\)个序列第前\(n\)小的序列和,然后把这\(n\)项当成一个新的序列。

很容易想,\(1,2,3\)的前\(n\)小序列和其实就是\(1,2\)的前\(n\)小的序列然后和\(3\)序列合并。(这个很好证)。

所以我们只要合并\(m-1\)次序列成一个序列,然后这个序列就是答案。

那么对于两个序列我们如何算出其前\(n\)小。

我们把第一个序列\(a\)排序,然后看第二个序列\(b\),很明显,第\(1\)小的肯定在\(a_{1}+b_{1},a_{1}+b_{2},...\)中产生,那么我们就建个堆,把这个丢进去。

然后对于最小的\(a_{1}+b_{i}\),那么第二小就会在上面那坨除\(a_{1}+b_{i}\)\(a_{2}+b_{i}\)中产生,再把\(a_{2}+b_{i}\)丢进堆就行了。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define  N  2100
using  namespace  std;
struct  node
{
    int  x,id/*表示是哪一行*/;
    node(int  xx,int  yy){x=xx;id=yy;}
};
inline  bool  operator<(node  x,node  y){return  x.x>y.x;}
priority_queue<node>ss;
int  a[N][N],n,m;
int  b[N],c[N],now[N];
void  merge(int  x1,int  x2)
{
    memcpy(b,a[x1],sizeof(b));memcpy(c,a[x2],sizeof(c));
    while(!ss.empty())ss.pop();
    sort(b+1,b+n+1);
    for(int  i=1;i<=n;i++)ss.push(node(b[1]+c[i],i)),now[i]=1;
    for(int  i=1;i<n;i++)
    {
        a[x2][i]=ss.top().x;int  x=ss.top().id;
        ss.pop();
        if(now[x]<n)ss.push(node(c[x]+b[++now[x]],x));
    }
    a[x2][n]=ss.top().x;
}
int  main()
{
    int  T;scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&m,&n);
        for(int  i=1;i<=m;i++)
        {
            for(int  j=1;j<=n;j++)scanf("%d",&a[i][j]);
        }
        if(m==1)
        {
            sort(a[1]+1,a[1]+n+1);
            for(int  i=1;i<n;i++)printf("%d ",a[m][i]);
            printf("%d\n",a[m][n]);
            continue;
        }
        for(int  i=2;i<=m;i++)merge(i-1,i);
        for(int  i=1;i<n;i++)printf("%d ",a[m][i]);
        printf("%d\n",a[m][n]);
    }
    return  0;
}

猜你喜欢

转载自www.cnblogs.com/zhangjianjunab/p/11737542.html
今日推荐