UVA 11997 K Smallest Sums (多路归并)

本文介绍了一种针对k*k矩阵的特定算法,该算法能够高效地找出所有k^k组合中前k个最小和。通过将问题分解为两两合并的形式,并使用优先队列来跟踪最小组合,从而实现了算法的设计。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:

kkkkk

分析:

n=2a,b
ai
1a[1]+b[1]<=a[1]+b[2]<=...<=a[1]+b[n]
....
na[n]+b[1]<=a[n]+b[2]<=...<=a[n]+b[n]
ka[k]+b[k]使(SB)S=a[k]+b[k]Bb
a(S,B+1)S=a[k]+b[k+1]=Sb[k]+b[k+1]
n

代码:

//
//  Created by TaoSama on 2015-11-04
//  Copyright (c) 2015 TaoSama. All rights reserved.
//
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <set>
#include <vector>

using namespace std;
#define pr(x) cout << #x << " = " << x << "  "
#define prln(x) cout << #x << " = " << x << endl
const int N = 1e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;

int n, a[755], b[755];

typedef pair<int, int> P;
void merge() {
    priority_queue<P, vector<P>, greater<P> > q;
    for(int i = 1; i <= n; ++i) q.push(P(a[i] + b[1], 1));
    for(int i = 1; i <= n; ++i) {
        P u = q.top(); q.pop();
        a[i] = u.first;
        int idx = u.second;
        if(idx < n)
            q.push(P(u.first - b[idx] + b[idx + 1], idx + 1));
    }
}

int main() {
#ifdef LOCAL
    freopen("C:\\Users\\TaoSama\\Desktop\\in.txt", "r", stdin);
//  freopen("C:\\Users\\TaoSama\\Desktop\\out.txt","w",stdout);
#endif
    ios_base::sync_with_stdio(0);

    while(scanf("%d", &n) == 1) {
        for(int i = 1; i <= n; ++i) scanf("%d", a + i);
        sort(a + 1, a + 1 + n);
        for(int i = 2; i <= n; ++i) {
            for(int j = 1; j <= n; ++j) scanf("%d", b + j);
            sort(b + 1, b + 1 + n);
            merge();
        }
        for(int i = 1; i <= n; ++i)
            printf("%d%c", a[i], " \n"[i == n]);
    }
    return 0;
}
### 关于四归并排序的图解说明 #### 四归并排序概述 四归并排序是一种扩展形式的多路归并排序,其基本思想与传统的2-归并排序相似。不同之处在于每次合并时不是将两个有序子序列合并为一个,而是将四个有序子序列合并为一个更大的有序序列[^5]。 #### 工作流程描述 假设初始序列为长度 $ N $ 的无序数组,则可以将其视为由 $ N $ 个长度为1的有序子序列组成。接着按照如下方式逐步完成排序: 1. 将每相邻的4个长度为1的子序列合并成一个长度为4(或更少)的有序子序列; 2. 继续对这些新的较长的有序子序列再次按上述方式进行分组和合并操作; 3. 不断重复此过程直到最终形成一个完整的长度为 $ N $ 的有序序列。 以下是具体的图示化表示: #### 图解实例展示 ##### 初始状态 假设有以下待排序列表 `[7, 2, 9, 1, 0, 3, 8, 4]` ,我们将它分成多个单元素的小数组: ``` [[7], [2], [9], [1], [0], [3], [8], [4]] ``` ##### 第一次合并 (每4个小数组合并) 现在把这八个单独的数值两两配对,并进一步组合成为四个较小范围内的已排序片段: ```python # 合并前 [[7, 2], [9, 1], [0, 3], [8, 4]] # 对每个小组内部进行局部排序后得到的结果 [[2, 7], [1, 9], [0, 3], [4, 8]] ``` ##### 第二次合并 (继续扩大规模至整个数据集) 下一步就是把这些已经部分整理好的区块再度联合起来构成更大区域上的顺序排列情况: ```python # 再次合并之前的状况 [[2, 7, 1, 9], [0, 3, 4, 8]] # 这些较大单元间执行全局排序后的成果展现出来 [[1, 2, 7, 9], [0, 3, 4, 8]] ``` 最后一步便是将这两个大块合为一体即可获得完全排好队列的形式: ```python # 总体上最后一次融合动作完成后呈现出来的样子 [0, 1, 2, 3, 4, 7, 8, 9] ``` 以上便是一个简单的四归并排序的过程演示。 #### 实现代码样例 下面给出一段 Python 版本实现该算法逻辑的例子供参考学习使用: ```python def merge_four_way(arr): if len(arr) <= 1: return arr mid1 = len(arr)//4 mid2 = mid1*2 mid3 = mid1*3 left = merge_four_way(arr[:mid1]) second = merge_four_way(arr[mid1:mid2]) third = merge_four_way(arr[mid2:mid3]) right = merge_four_way(arr[mid3:]) return four_way_merge(left, second, third, right) def four_way_merge(l1,l2,l3,l4): result = [] while l1 or l2 or l3 or l4: smallest = None for lst in [l1, l2, l3, l4]: if lst and (smallest is None or lst[0]<smallest[0]): smallest = lst if smallest: result.append(smallest.pop(0)) return result ``` 通过这样的函数定义我们可以轻松调用 `merge_four_way()` 方法传入任意未加工的数据集合从而获取到经过精确计算处理之后返回来的理想型态下的输出结果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值