《k路并归问题》

模型一:给定n个数组,让你求n个数组中最小的k个数。

这里显然可以用到一种贪心的维护思路。利用小顶堆。

先将n个数组排成有序数组。

将每个数组的最小的那个数放入小顶堆中。

然后我们开始维护,很显然对于某一个数组中的某个数,如果它要被放入在小顶堆中,那他在该数组中前面位置的那个数,显然已经在队列中。

因为它前面的那个数比他小,按照最小的思路,肯定是先放入最小的。

 

模型二:UVA - 11997

给定k个数组,每个数组中有k个数,求在每个数组中选一个数,组成的和的最小的k个。

考虑递推的思路,假定我们当前维护到了第i个数组,且我们知道了前i - 1个数组每个取一个组成的最小k种方案。

那么我们就可以转移过来。转移的思路依旧考虑有序数组,我们先用第i个数组的最小的数和前k个最小的组成新的k个数。

放在小顶堆中,然后我们依旧用上面的维护思路,假定我们要变动的数在数组中的位置为p,那么下一个放入的肯定是p + 1和当前的组合。

所以要记录下下标。

// Author: levil
#include<iostream>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<math.h>
#include<stack>
#include<map>
#include<limits.h>
#include<vector>
#include<string.h>
#include<string>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> pii;
const int N = 1e5 + 5;
const int M = 1e7 + 5;
const LL Mod = 1e9 + 7;
#define pi acos(-1)
#define INF 1e12
#define dbg(ax) cout << "now this num is " << ax << endl;
namespace FASTIO{
    inline LL read(){
        LL x = 0,f = 1;char c = getchar();
        while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
        while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
        return x*f;
    }
}
using namespace FASTIO;

vector<int> vec[1005];
LL ans[1005];
int main() {
    int k;
    while(~scanf("%d",&k)) {
        for(int i = 1;i <= k;++i) {
            vec[i].clear();
            for(int j = 1;j <= k;++j) {
                int x;scanf("%d",&x);
                vec[i].push_back(x);
            }
            sort(vec[i].begin(),vec[i].end());
        }
        for(int i = 1;i <= k;++i) ans[i] = vec[1][i - 1];
        for(int i = 2;i <= k;++i) {
            priority_queue<pii,vector<pii>,greater<pii> >Q;
            for(int j = 1;j <= k;++j) {
                Q.push(pii{ans[j] + vec[i][0],0});
            }
            for(int j = 1;j <= k;++j) {
                LL val = Q.top().first;
                int pos = Q.top().second;
                Q.pop();
                if(pos + 1 < k) Q.push(pii{val - vec[i][pos] + vec[i][pos + 1],pos + 1});//删去p,与p + 1组合
                ans[j] = val;
            }
        }
        for(int i = 1;i <= k;++i) printf("%lld%c",ans[i],i == k ? '\n' : ' ');
    }

    system("pause");
    return 0;
}
View Code

 

posted @ 2021-07-17 16:39  levill  阅读(50)  评论(0编辑  收藏  举报