UVa 11997 K Smallest Sums (K路归并)
K Smallest Sums
Description
You’re given k arrays, each array has k integers. There are k k 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).
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
Sample Output
9 10 12
2 2
题意:给你K个数组,每个数组有K个数,从每个数组中选一个数,一共有K^K个组合,求最小的K个数
分析:先看一个简单的版本:K=2时,这个问题就可以转化为多路归并的问题了,建一个二维数组:
1: a1+b1<=a2+b1<=a3+b1<=.......<=an+b1
2: a1+b2<=a2+b2<=a3+b2<=.......<=an+b2
............
n: a1+bn<=a2+bn<=a3+bn<=.......<=an+bn
这个我们可以用一个二元组来表示(s,k),s表示ai+bj,k=j。然后初始将(ai,b1)的所有组合放到优先队列里面,每次取出一个,将a的下标加一,再放入优先队列中,做n次即可。
对于K个,我们只需两两进行上面的操作就行了。
#include<bits/stdc++.h> using namespace std; const int MAXN = 1000; struct Node { int sum,k;//k代表b的下标 bool operator<(const Node& rhs) const { return sum>rhs.sum; } }; int a[MAXN][MAXN]; void Merge(int* A,int* B,int* C,int n) { priority_queue<Node> q; for(int i=1;i<=n;i++) { Node aa; aa.sum=A[i]+B[1]; aa.k=1; q.push(aa); } for(int i=1;i<=n;i++) { Node aa=q.top(); q.pop(); C[i]=aa.sum; int k=aa.k; if(k<n) { aa.sum=aa.sum-B[k]+B[k+1]; aa.k++; q.push(aa); } } } int main() { int n; while(scanf("%d",&n)!=EOF) { for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) scanf("%d",&a[i][j]); sort(a[i]+1,a[i]+n+1); } for(int i=2;i<=n;i++) Merge(a[1],a[i],a[1],n); for(int i=1;i<=n;i++) { printf("%d",a[1][i]); if(i!=n) printf(" "); else printf("\n"); } } return 0; }