题目

July 8, 2021 · View on GitHub

给定 m 个序列,每个包含 n 个非负整数。

现在我们可以从每个序列中选择一个数字以形成具有 m 个整数的序列。

很明显,我们一共可以得到 nm个这种序列,然后我们可以计算每个序列中的数字之和,并得到 nm 个值。

现在请你求出这些序列和之中最小的 n 个值。

输入格式
第一行输入一个整数 T,代表输入中包含测试用例的数量。

接下来输入 T 组测试用例。

对于每组测试用例,第一行输入两个整数 m 和 n。

接下在 m 行输入 m 个整数序列,数列中的整数均不超过 10000。

输出格式
对于每组测试用例,均以递增顺序输出最小的 n 个序列和,数值之间用空格隔开。

每组输出占一行。

数据范围
0<m≤1000,
0<n≤2000

输入样例:

1
2 3
1 2 3
2 2 3

输出样例:

3 3 4

参考答案

#include <algorithm>
#include <cstring>
#include <iostream>
#include <queue>
#include <vector>

using namespace std;

typedef pair<int, int> PII;

const int N = 2e3 + 10;

int n, m;
// a和b是每次需要合并的序列, c是中间临时缓存的序列
int a[N], b[N], c[N];

void work() {
    // 默认是大根堆, 这样可以变成小根堆
    priority_queue<PII, vector<PII>, greater<PII>> heap;
    for (int i = 0; i < n; i++) {     // 小根堆, 堆顶就是最小值
        heap.push({a[0] + b[i], 0});  // push进去的是一个pair
    }
    for (int i = 0; i < n; i++) {
        auto t = heap.top();
        heap.pop();
        int s = t.first, p = t.second;
        c[i] = s;
        heap.push({s - a[p] + a[p + 1], p + 1});
    }
    // memcpy最后一个参数是字节, 一个int包含4个字节
    memcpy(a, c, 4 * n);  //拷贝数组
    // for (int i = 0; i < n; i++) {
    //     a[i] = c[i];
    // }
}

int main() {
    int T;
    cin >> T;
    while (T--) {
        cin >> m >> n;
        for (int i = 0; i < n; i++) {
            cin >> a[i];  //先读入一行
        }
        sort(a, a + n);
        for (int i = 1; i < m; i++) {
            for (int j = 0; j < n; j++) {
                cin >> b[j];
            }
            // sort(b, b + n);
            work();  //每次合并两组, 共合并m-1次
        }
        for (int i = 0; i < n; i++) {
            if (i > 0) {
                cout << " ";
            }
            cout << a[i];
        }
        cout << endl;
    }
    return 0;
}