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;
}