UVA-11997 - K Smallest Sums(优先队列)

刘汝佳新书---训练指南

题意:有K个整数数组,包含K个元素。在每个数组中取一个元素加起来,可以得到k^k个和。求这些和中最小的K个值

分析:这题有简化版本的,即2个整数数组A,B,包含K个元素,在每个数组中取一个元素加起来,可以得到k^2个和,求这些和中最小的K个值。

我们需要把这k^2个和组织成如下k个有序表.

表1:A1+B1<=A1+B2<=......<=A1+Bk

表2: A2+B1<=A2+B2<=......<=A2+Bk

表k:Ak+B1<=AK+B2<=......<=Ak+Bk

我们可以用二元组(s,b)来表示一个元素即s=Aa+Bb;为什么不保存A的下标a呢?因为我们用不到a的值。如果我们需要元素(s,b)在表a的下一个元素(s',b+1).只需要计算s'=s+B[b+1]-B[b];

这样我们先将K个表的第一个元素压入优先队列,这样队列中就用k个元素了。然后从队列中出一个值,就压入这个值所在表的下一个元素,直到k个值都出了优先队列。这样就得到k个最小值了。。

然后对与K个数组。我们只需两两合并即可。

// File Name: 11997.cpp
// Author: zlbing
// Created Time: 2013/3/8 20:19:01

#include<iostream>
#include<string>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<set>
#include<map>
#include<vector>
#include<cstring>
#include<stack>
#include<cmath>
#include<queue>
using namespace std;
#define CL(x,v); memset(x,v,sizeof(x));
#define INF 0x3f3f3f3f
#define LL long long
#define REP(i,n) for(int i=0;i<n;i++)
#define REP1(i,n) for(int i=1;i<n+1;i++)
#define MAXN 1000
int G[MAXN][MAXN];
int k;
struct Item{
    int s,b;
    bool operator <(const Item& r)const{
        return s>r.s;
    }
};
void merge(int *A,int *B,int *C){
    int cnt=0;
    priority_queue<Item> Q;
    for(int i=0;i<k;i++)Q.push((Item){A[i]+B[0],0});
    while(!Q.empty()){
        Item t=Q.top();
        Q.pop();
        C[cnt++]=t.s;
        if(t.b+1<k)Q.push((Item){t.s+(B[t.b+1]-B[t.b]),t.b+1});
        if(cnt==k)break;
    }
    //for(int i=0;i<k;i++)printf("%d ",C[i]);
}
int main(){
    while(~scanf("%d",&k))
    {
        REP(i,k){
            REP(j,k)
                scanf("%d",&G[i][j]);
            sort(G[i],G[i]+k);
        }
        REP1(i,k-1)merge(G[0],G[i],G[0]);
        REP(i,k)
            if(i==0)printf("%d",G[0][i]);
            else printf(" %d",G[0][i]);
        printf("\n");
    }
    return 0;
}

 

posted @ 2013-03-08 21:12  z.arbitrary  阅读(1194)  评论(4编辑  收藏  举报