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个最小和的值。
思路:先看简化版,求两个长度为n的有序表A和B,分别在A和B取一个数相加,求前n小的和。
简化版用优先队列即可实现:
A1+B1 <= A1+B2 <= A1+B3 <= ---
A2+B1 <= A2+B2 <= A2+B3 <= ---
------------------------------
只需在优先队列中先存入A1+B1 A2+B1 --- An+B1,然后出一个数Ax+By,就推入Ax+By+1、
k个有序表,只需要两两合并即可。
#include <iostream> #include <cstdio> #include <cstring> #include <queue> #include <algorithm> using namespace std; #define maxn 770 struct Item { int s,b;//s = A[a] + B[b]; Item(int ss,int bb):s(ss),b(bb){} bool operator < (const Item & a) const { return s > a.s; } }; void merge(int * A,int * B,int * C,int n) { 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(); C[i] = item.s; int b = item.b; if(b + 1 < n) q.push(Item(item.s - B[b] + B[b+1],b+1)); } } int A[maxn][maxn]; int main() { int n; while(scanf("%d",&n)!=EOF) { for(int i = 0;i < n;i++) { for(int j = 0;j < n;j++) { scanf("%d",&A[i][j]); } sort(A[i],A[i]+n); } for(int i = 1;i < n;i++) merge(A[0],A[i],A[0],n); printf("%d",A[0][0]); for(int i = 1;i < n;i++) printf(" %d",A[0][i]); printf("\n"); } return 0; }