【优先队列之多路合并】UVA - 11997 K Smallest Sums

Source : UVA - 11997 K Smallest Sums

http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=18702

题意

有k个整数数组,各包含k个元素,从每个数组中选取一个元素加起来,可以得到k^k个和,求这些和中最小的k个值。

示例

Sample Input

3

1 8 5

9 2 5

10 7 6

2

1 1

1 2

Sample Output

9 10 12

2 2


思路

二路归并构建二维平面表:

表1:A1+B1<=A1+B2<=A1+B3……表2:A2+B1<=A2+B2<=A2+B3…………表n:An+B1<=An+B2<=An+B3……

首先将第一列入队,第一列的最小值即为全局的最小值;接下来定位到最小值的那一行,跳过这一个元素,把下一个元素入队,始终保持priority_queue中有n个元素,队首元素即为全局下一小的元素和,记录即可。

多路归并就要构建三位立体表:想象下

k×k×k的立方体表格

逐层二路合并即可。

★ 参考刘汝佳《算法竞赛入门经典训练指南》page 190


参考代码

#include<bits/stdc++.h>
using namespace std;

const int _max = 750 + 10;
int n,A[_max],B[_max];
struct Item{
  int s,b;//(s,b) s = Aa + Bb
  Item (){}
  Item(int s,int b):s(s) , b(b){}//构造函数
  bool operator < (const Item& a) const{//定义优先级
    return s > a.s;
  }
};
priority_queue<Item>pq;
Item item;

void merge(int A[],int B[],int C[]){//二路归并,前n个最小和存于C[]
  while(!pq.empty()) pq.pop();
  for(int i = 0; i < n; ++ i){
    item = Item(A[i] + B[0],0);
    pq.push(item); //第一列元素入队
  }
  for(int i = 0; i < n; ++ i){//O(nlogn)
    item = pq.top();pq.pop();
    C[i] = item.s;//第一列最小的一定是全局最小,跳过它读取同一行的下一个元素入队,循环n次
    int b = item.b;
    if(b + 1 < n) pq.push(Item(item.s - B[b] + B[b+1],b + 1));
  }
}

int main(){
 #ifndef ONLINE_JUDGE
 freopen("input.txt","r",stdin);
 #endif // ONLINE_JUDGE
 while(scanf("%d",&n) == 1){
    for(int i = 0; i < n; ++ i) //先读一路数据
       scanf("%d",A + i);
    sort(A , A + n);
    for(int i = 1; i < n; ++ i){ //以二路为基础做多路归并
        for(int j = 0; j < n; ++ j) scanf("%d",B+j);
        sort(B,B+n);
        merge(A,B,A);//A[]元素只用做初始化,所以在合并过程可以直接把结果存储到A中
    }
    printf("%d",A[0]);//输出格式
    for(int i = 1; i < n; ++ i) printf(" %d",A[i]);
    printf("\n");
 }
 return 0;
}
  • 加粗 Ctrl + B
  • 斜体 Ctrl + I
  • 引用 Ctrl + Q
  • 插入链接 Ctrl + L
  • 插入代码 Ctrl + K
  • 插入图片 Ctrl + G
  • 提升标题 Ctrl + H
  • 有序列表 Ctrl + O
  • 无序列表 Ctrl + U
  • 横线 Ctrl + R
  • 撤销 Ctrl + Z
  • 重做 Ctrl + Y

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-11-08 11:05:05

【优先队列之多路合并】UVA - 11997 K Smallest Sums的相关文章

UVa 11997 K Smallest Sums 优先队列&amp;&amp;打有序表&amp;&amp;归并

UVA - 11997 K Smallest Sums Time Limit: 1000MS   Memory Limit: Unknown   64bit IO Format: %lld & %llu Submit Status 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 o

(DS 《算法竞赛入门经典》)UVA 11997 K Smallest Sums

题目大意:有k个数组,每个数组选取一个数,组成k^k个数.在这k^k个数中选择最小的前k个数 解题思路: 1.如果只有k个数组,那么最后得到的最小的前k个数应该可以由前两个数组得到的最小k个数与第三个数组 按规则运算后得到. 2.如果每个数组只有3个数.那么前两个数组(a:(a0,a1,a2)    b:(b0,b1,b2,a与b数组都已经有序)运算后有的结果矩阵如下: a0+b0,a0+b1,a0+b2 a1+b0,a1+b1,a1+b2 a2+b0,a2+b1,a2+b2 在这个矩阵中,a0

UVA 11997 K Smallest Sums 优先队列 多路合并

vjudge 上题目链接:UVA 11997 题意很简单,就是从 k 个数组(每个数组均包含 k 个正整数)中各取出一个整数相加(所以可以得到 kk 个结果),输出前 k 小的和. 这时训练指南上的一道题,这道题的简化版其实在 15 年的广东省省赛出现过,当时是以送分题的形式出现的,可我还是没能做出来,归根到底还是看书不够,接触的题型不够多. *************************************************************大白书上的讲解开始*******

uva 11997 K Smallest Sums 优先队列处理多路归并问题

题意:K个数组每组K个值,每次从一组中选一个,共K^k种,问前K个小的. 思路:优先队列处理多路归并,每个状态含有K个元素.详见刘汝佳算法指南. 1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<stack> 5 #include<queue> 6 #include<vector> 7 #include<map> 8 #includ

uva 11997 K smallest sums (优先队列 多路归并)

算法入门经典 训练指南 p189 #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<queue> using namespace std; struct Item { int s,b; Item(int s,int b) :s(s),b(b) {} bool operator < (const Item&rhs) co

UVA 11997 K Smallest Sums (多路归并)

从包含k个整数的k个数组中各选一个求和,在所有的和中选最小的k个值. 思路是多路归并,对于两个长度为k的有序表按一定顺序选两个数字组成和,(B表已经有序)会形成n个有序表 A1+B1<=A1+B2 A2+B1<=A2+B2 ... An+B1<=An+B2 在学习的归并排序的时候是把两个有序的表合并成一个,每次比较只在两个元素之间进行,所以只需要用>比较, 而现在需要同时合并n个有序表,优先队列(堆)就派上用场了.类似归并排序用i和j维护有序表当前考虑元素, 合并的时候,每次取出的

UVA 11997 K Smallest Sums 优先队列+归并 STL

题目链接: UVA...... 题目描述: 有K组数, 每组数有K个, 所以每组数各选一个加和有k^k种情况, 要求输出其中的最小的前k种, 从小到大输出 解题思路: 首先对于两个数组取前K个, 构造二元组(s, b) 其中s = Aa + Bb , a, b 为下标. 为什么不用三元组(s,a,b)呢, 因为二元组完全可以表示三元组, 下一个元素就是s+B[i+1]-B[i] . 我们需要把这k^2个和组织成如下k个有序表.(A, B是有序的哦) 表1:A1+B1<=A1+B2<=.....

优先队列 UVA 11997 K Smallest Sums

题目传送门 题意:训练指南P189 分析:完全参考书上的思路,k^k的表弄成有序表: 表1:A1 + B1 <= A1 + B2 <= .... A1 + Bk 表2:A2 + B1 <= A2 + B2 <= ...  A2 + Bk ....... 表k:Ak + B1 <= Ak + B2 <= ...  Ak + Bk 可以维护一个k长度的数组表示当前的前k小的数字和,当第i行的数组读入时,先push第一个,也就是最小的,然后可以更新成第二个,就是 - B[i]

【UVA 11997 K Smallest Sums】优先级队列

来自<训练指南>优先级队列的例题. 题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=18702 题意:给定k个整数数组,各包含k个元素.在每个数组中取一个元素加起来,可以得到kk个和,求这些和中最小的k个值(不去重). 数据范围:k [2, 750] 思路:暴力枚举k^k不可取. “先来看问题的简化版:给出两个长度为k的数组A和B,分别在A和B中任取一个数并相加,可以得到k^2个和,求这些和中最小的k个.” 首先