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.
题目大意就是给你n组数,每组有n个数字,从每一组中选出一个数字加起来都可以获得一个值,求前n小的值。做法就是优先队列进行多路归并,1.首先我们看看如何找最小的一个组合,只需要将每组数字重新排列成有序的,每组选择最小的的那一个加起来就是最小的组合值,而将这个最小组合中的某一个数字换成其所在数组的第二小的数字就有可能得到第二小的组合。2.当我们求出了两组数字组合而成的前n小数字之后,若数组变成了三个,只需要用之前组合而成的前n小的数字与第三个数组进行组合就能找到新的前n小数组组合了。3.所以我们固定第一个数列,用后面的每一个数列来更新其与数列一的组合前n小,并存于数列一中,进行n-1次更新之后数列一就是前n小的组合值了。4.对于固定的数组a和前来合并的数组b,我们枚举a的数字将其与b[0]相加放入优先队列中,每次取出队列中值最小的,并将这个a+b[x]的组合的x+1继续放入队列中,就可以维护出前n小的组合。
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <queue>
#include <vector>
#include <algorithm>
using namespace std;
#define ll long long
#define N 100005
int a[755];
int b[755];
int k;
struct line{
int s,b;
bool operator < (line b)const{
return s>b.s;
}
};
void merge(int *a, int *B, int *c){
priority_queue<line> que;
for (int i = 0; i < k; i++){
que.push({ a[i] + B[0], 0 });
}
for (int i = 0; i < k; i++){
line cnt = que.top(); que.pop();
c[i] = cnt.s;
if (cnt.b < k - 1)que.push({ cnt.s - B[cnt.b] + B[cnt.b + 1], cnt.b + 1 });
}
}
int main(){
while (~scanf("%d", &k)){
for (int i = 0; i < k; i++){ scanf("%d", &a[i]); }
sort(a, a + k);
for (int i = 1; i < k; i++){
for (int i = 0; i < k; i++){
scanf("%d", &b[i]);
}
sort(b, b + k);
merge(a, b, a);
}
for (int i = 0; i < k; i++){
printf("%d", a[i]);
if (i < k - 1)printf(" ");
}
printf("\n");
}
return 0;
}