UVA 11997 K Smallest Sums(优先队列)

题目:
You're given k arrays, each array has k integers. There are kk ways to pick exactly one element in each array and calculate the sum of the integers. Your task is to find the k smallest sums among them.


Input


There will be several test cases. The first line of each case contains an integer k (2<=k<=750). Each of the following k lines contains k positive integers in each array. Each of these integers does not exceed 1,000,000. The input is terminated by end-of-file (EOF). The size of input file does not exceed 5MB.


Output


For each test case, print the k smallest sums, in ascending order.


Sample Input


3
1 8 5
9 2 5
10 7 6
2
1 1
1 2
Output for the Sample Input


9 10 12
2 2


题目是要你求k 个数组。由这些数组每个都取出一个数字,可以组成K的K次方的排列组合出来 。
求其中最小的K个值。
要用到优先队列。
我从白皮书上看到这道题目的时候,也是看不懂。后面明白了。
首先求这些数组的最小和的时候,要先排序,排序之后,你才知道你加入优先队列的数是当前
的最小值,除了优先队列的数,先筛选出优先队列的最小值。
其中这个公式比较关键:S=Aa+Bb;
那么下个添加的数字一定是S'=Aa+Bb+1=Aa+Bb-Bb+Bb+1=S-Bb+Bb+1;
至于为什么是这个,你可以将排好序的两组数进行手动的计算一下,就会发现的确如此。

这里也就是只要用到B数组的下标的原因。

#include<stdio.h>
#include<algorithm>
#include<queue>
using namespace std;
int n;
const int maxn=768;
int A[maxn],B[maxn];
struct Item{
    int s,b;
    Item(int s,int b):s(s),b(b){}
    bool operator<(const Item & C)const
    {
        return s>C.s;
    }
};
void merge()
{
    priority_queue<Item> q;
    for(int i=0;i<n;i++){
        q.push(Item(A[i]+B[0],0));
    }

    for(int i=0;i<n;i++){
        Item item=q.top();
        q.pop();
        A[i]=item.s;
        int b=item.b;
        if(b+1<n)q.push(Item(item.s-B[b]+B[b+1],b+1));
    }
}
int main()
{
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++)
                if(i==0) scanf("%d",&A[j]);
                else scanf("%d",&B[j]);
            if(i==0) sort(A,A+n);
            else sort(B,B+n);
            if(i>0)
                merge();
        }
        for(int i=0;i<n;i++)
            printf("%d%c",A[i],i==n-1?'\n':' ');

    }
    return 0;
}









你可能感兴趣的:(UVA 11997 K Smallest Sums(优先队列))