Uva11997

题意

给你 k 个数组,在每个数组中取出一个元素可以得到 k^k 个数,求这其中最小的 k 个数


 数据范围显然是不能暴力的,想作法也只有一些乱搞做法

首先考虑只有两个数组的情况,就是当 k = 2 ,数组长度为 n 时,求出这其中最小的 n 个值

首先排序,列出一下一些表:

a1 + b1, a1 + b2, a1 + b3, ...

a2 + b1, a2 + b2, a2 + b3, ...

a3 + b1, a3 + b2, a3 + b3, ...

...

an + b1, an + b2, an + b3, ...

我们也很容易在这些行/列之间画出小于号

这样一个位置上的数可能成为答案集合当中的数当且仅当它左边或上边的数被选了

后边就脑残了= =

其实就把第一列全部塞进堆里,每个元素记录一个下标就好了,每次取出来这个数就把它右边的数也入堆

是 O(klogk) 的

现在考虑这道题

多维?

只需要每次合并两个

最后按大小找就好了


 

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<cstdio>
#include<queue>
using namespace std;

const int MAXK = 755;

struct Node{
    int sum, pos;
    Node(int s = 0, int b = 0){sum = s; pos = b;}
    bool operator < (const Node& b) const {
        return sum > b.sum;
    }
};
int k;
int a[MAXK][MAXK];

inline void Merge(int *x, int *y, int *dst) {
    priority_queue<Node> q;
    for(int i = 1; i <= k; ++i) q.push(Node(x[i] + y[1], 1));
    for(int i = 1; i <= k; ++i) {
        Node cur = q.top(); q.pop();
        dst[i] = cur.sum;
        ++cur.pos;
        cur.sum = cur.sum - y[cur.pos - 1] + y[cur.pos];
        if(cur.pos <= k) q.push(cur);
    }
    return;
}

int main() {
    while(scanf("%d", &k) != EOF) {
        for(int i = 1; i <= k; ++i) {
            for(int j = 1; j <= k; ++j) 
                scanf("%d", &a[i][j]);
            sort(a[i] + 1, a[i] + k + 1);
        }
        for(int i = 2; i <= k; ++i) {
            Merge(a[1], a[i], a[1]);
        }
        for(int i = 1; i < k; ++i) printf("%d ", a[1][i]);
        printf("%d\n", a[1][k]);
    }
    return 0;
}

  

转载于:https://www.cnblogs.com/xcysblog/p/9696932.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值