poj 2442 Sequence(堆)

190 篇文章 2 订阅
15 篇文章 0 订阅

题面

题意

给出一个m*n的矩阵,每行选择一个数相加,问所得的n个最小值是多少。

方法

将所有数一起处理必然会有漏洞,无法保证答案的正确或是时间,故可以一行一行处理,因为多考虑一行后的n个最小数必然由考虑这一行之前的n个最小值与这一行上的一些数相加得到,因而每次只需记录考虑上面几行后的最小值即可,问题就转换为了求两行上一些数相加的所有和中的最小的n个值。
这个问题可以用堆解决,因为两个序列都是升序,若a[i]+b[j]是其中一个最小值,那么a[i-1]和b[j-1]也是,以此性质,我们可以把a[1]与b中所有数的和加到堆里,每取出最小值,把a序列中的下一个数与b中那个数的和加到堆里:
例:a[1]+b[1]出堆后,将a[2]+b[1]加到堆里。

代码

#include<iostream>
#include<cstdio>
#include<queue>
#include<algorithm>
#define P pair<int,int>
#define mp make_pair
#define fi first
#define se second
using namespace std;

int T,n,m,num[110][2010],ans[2010],now[2010],tmp[2010];
priority_queue<P,vector<P>,greater<P> >pq;
P tmp2;

void read(int &u)
{
    u=0;
    register char ch=getchar();
    while(ch<'0') ch=getchar();
    while(ch>='0'&&ch<='9')
    {
        u*=10,u+=ch-'0',ch=getchar();
    }
}

int main()
{
    register int i,j,k;
    cin>>T;
    while(T--)
    {
        read(m),read(n);
        for(i=1;i<=m;++i)
        {
            for(j=1;j<=n;++j)
            {
                read(num[i][j]);
            }
            sort(num[i]+1,num[i]+n+1);
        }
        for(i=1;i<=n;++i)
        {
            ans[i]=num[1][i];
        }

        for(i=2;i<=m;++i)
        {
            for(;!pq.empty();pq.pop());
            for(j=1;j<=n;++j)
            {
                now[j]=1;
                pq.push(mp(ans[j]+num[i][1],j));
            }
            for(j=1;j<=n;++j)
            {
                ans[j]=pq.top().fi;
                tmp2=pq.top();
                pq.pop();
                now[tmp2.se]++;
                tmp2.fi+=num[i][now[tmp2.se]]-num[i][now[tmp2.se]-1];
                pq.push(tmp2);
            }
        }
        for(i=1;i<=n;++i)
        {
            printf("%d ",ans[i]);
        }
        puts("");
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值