K Smallest Sums 多路归并优先队列

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个和。求这些和中最小的K个值

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

将数组A,B排序;

A : A1  A2 ......  Ak

B:     B1  B2 ......   Bk

如果一个一个加起来取最小值很费时也很费空间,那么我们需要这样简化(非常巧妙,也很难想到):

把这k^2个和组织成如下k有序表

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

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

……

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

用数组A来记录,用优先队列来维护和;

优先队列初始化:用s来记录A1+Bi的和,即 s = A1 + Bi ;

取出其中最小的更新A数组,在通过这个最小值寻求下一个最小值放入队列(这里是重点!) 即 s' = s - Bi + Bi+1;

最终通过两两合并得到最后的解


代码如下:

#include <iostream>
#include <cstdio>
#include <queue>
#include <algorithm>
#define maxn 760
using namespace std;

int n;
int a[maxn][maxn];

struct node
{
    int sum;
    int b;
    bool operator <( const node& a) const
    {
        return sum > a.sum;
    }

};

void merge(int *A,int *B,int *C,int n)
{
    priority_queue <node> q;
    node s;
    for(int i = 0 ; i < n ;i ++) // 队列赋初值
    {
        s.sum = A[i] + B[0];
        s.b = 0;
        q.push(s);
    }
    for(int i = 0 ; i < n ;i++ )
    {
        node item = q.top();//取出队列中的最小值
        q.pop();
        C[i] = item.sum;//用a[i]记录
        int b = item.b;
        if(b + 1 < n)//用最小的来找下一个最小的(太难想到了)
        {
            s.sum =item.sum - B[b] + B[b+1] ;
            s.b = b + 1;
            q.push(s);
        }
    }
}

int main()
{
    while(scanf("%d",&n) != EOF)
    {
        for(int i = 0 ; i < n ;i++)
        {
            for(int j = 0; j < n; j++)
                cin >> a[i][j];
            sort(a[i],a[i]+n);//每一行排序
        }
        for(int k = 1; k < n ; k++) //两两合并
            merge(a[0],a[k],a[0],n);
        cout << a[0][0];
        for(int j = 1; j < n ; j++)
            cout << " " << a[0][j];
        cout << endl;
    }

    return 0;
}



猜你喜欢

转载自blog.csdn.net/Xuedan_blog/article/details/79767377