UVA11997 K Smallest Sums(并归,优先队列)

题意:有k行数,每行k个数,从每行中抽出一个数,相加得到sum, 求这样的sum的前k小数,并输出。

分析:大白书(刘汝佳 著)优先队列章节,

假设现在有两行A,B(从小到大排序),求前k小,则:

A1+B1<=A1+B2<=....A1+Bn

A2+B1<=A2+B2<=....A2+Bn

A3+B1<=A3+B2<=....A3+Bn

...........  

用一个优先队列来维护前k小的值,先把(A1+B1),(A2+B1),(A3+B1)...放入队列,但这k个数不一定是前k小,唯一可以确定的是(A1+B1)是第一小的,

A1+B1肯定是最小的,则出队并保存。此时队首元素是(A2+B1),但不一定是次小值,次小值为min(A2+B1,A1+B2),于是,就把(A1+B2)压入队列,队首元素就为次小值。以此类推,每次将队首元素出队,并保存,然后压入该元素的右边元素到队列,如队首为Aa+Bb,出队->保存->将(Aa+B(b+1))入队。这样就能依次找到前k小的值。

那么k行咋办呢?其实可以把A,B数组求出的前k小值保存到A数组,然后加入下一个数组,以相同的方式,可以求出k行的最小前k个和。

#include <iostream>
#include <stdio.h>
#include <math.h>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <string.h>
#include <map>
#include <set>
using namespace std;
int mat[751][751];
class node
{
public:
    int s,b;
    node(int ss,int bb):s(ss),b(bb){}//s=Aa+Bb,b存的是Bb 的下标
    bool operator <(const node& x)const
    {
        return s>x.s;
    }
};
int main()
{


    int k,i,j;
    while(cin>>k)
    {

        for(i=1;i<=k;i++)
        {
            for(j=1;j<=k;j++)
            {
                cin>>mat[i][j];

            }
            sort(mat[i]+1,mat[i]+1+k);
        }
        for(i=2;i<=k;i++)
        {
            priority_queue<node>q;

            for(j=1;j<=k;j++)
            {
               q.push(node(mat[1][j]+mat[i][1],1));
            }


           for(j=1;j<=k;j++)
           {
               node tx=q.top();

               q.pop();
               mat[1][j]=tx.s;
               if(tx.b+1<=k)
                q.push(node(tx.s-mat[i][tx.b]+mat[i][tx.b+1],tx.b+1));
                //队首为s=Aa+Bb,入队的下一个元素为s'=s-Bb+B(b+1)=Aa+B(b+1);
           }

        }
        for(j=1;j<=k;j++)
            {
                if(j!=1)cout<<" ";
               cout<<mat[1][j];
            }
       cout<<endl;
    }
    return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值