poj 2442 Sequence(堆)

来源:互联网 发布:安卓上运行windows游戏 编辑:程序博客网 时间:2024/06/05 00:46

题面

题意

给出一个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 secondusing 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("");    }}