多路归并优先队列——UVA 11997

K Smallest Sums

You‘re given k arrays, each array has k integers. There are kk ways to pick exactly one element in each array and calculate the sum of the integers. Your task is to find the k smallest sums among them.

Input

There will be several test cases. The first line of each case contains an integer k (2<=k<=750). Each of the following k lines contains k positive integers in each array. Each of these integers does not exceed 1,000,000. The input is terminated by end-of-file
(EOF). The size of input file does not exceed 5MB.

Output

For each test case, print the k smallest sums, in ascending order.

Sample Input

3
1 8 5
9 2 5
10 7 6
2
1 1
1 2

Output for the Sample Input

9 10 12
2 2

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

分析:这题有简化版本的,即2个整数数组A,B,包含K个元素,在每个数组中取一个元素加起来,可以得到k^2个和,求这些和中最小的K个值。

我们需要把这k^2个和组织成如下k个有序表.

表1:A1+B1<=A1+B2<=......<=A1+Bk

表2: A2+B1<=A2+B2<=......<=A2+Bk

表k:Ak+B1<=AK+B2<=......<=Ak+Bk

我们可以用二元组(s,b)来表示一个元素即s=Aa+Bb;为什么不保存A的下标a呢?因为我们用不到a的值。如果我们需要元素(s,b)在表a的下一个元素(s‘,b+1).只需要计算s‘=s+B[b+1]-B[b];

这样我们先将K个表的第一个元素压入优先队列,这样队列中就用k个元素了。然后从队列中出一个值,就压入这个值所在表的下一个元素,直到k个值都出了优先队列。这样就得到k个最小值了

别人的讲解,非常详细!

#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<map>
#include<queue>
#include<stack>
#include<vector>
#include<algorithm>
#include<cstring>
#include<string>
#include<iostream>
#define ms(x,y) memset(x,y,sizeof(x))
const int MAXN=750+10;
const int INF=1<<30;
using namespace std;
int a[MAXN];
int b[MAXN];

struct Pair
{
	int val, dex;
	Pair(){}
	Pair(int v, int d):val(v),dex(d){}
	friend bool operator < (Pair const p1, Pair const p2)
	{
		return p1.val > p2.val;
	}
};

int main()
{
	//freopen("in.txt","r",stdin);
	int n;
	while(~scanf("%d", &n))
	{
		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);
			int cnt = 0;
			priority_queue<Pair>pq;
			for(int v=0; v<n; v++)
				pq.push(Pair(a[v] + b[0], 0));
			Pair p;
			while(!pq.empty())
			{
				p = pq.top();
				a[cnt++] = p.val;
				if(cnt == n) break;
				pq.pop();
				p.dex++;
				pq.push(Pair(p.val - b[p.dex-1] + b[p.dex], p.dex));
			}
		}
		printf("%d", a[0]);
		for(int i=1; i<n; i++)
			printf(" %d", a[i]);
		printf("\n");
	}
	return 0;
}
时间: 2024-11-13 09:06:23

多路归并优先队列——UVA 11997的相关文章

【优先队列之多路合并】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 思路 二路归并构建二维平面表:

优先队列 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 优先队列处理多路归并问题

题意: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 优先队列 多路合并

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

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+优先队列用于多路归并

题目链接:点击进入 先考虑两个数组A,B的情况,这样总共有n^2种情况;将A,B数组排序后,我们可以将所有情况组织成n张表: 表1: A[1]+B[1]<=A[1]+B[2]<=--<=A[1]+B[n]. 表2: A[2]+B[1]<=A[2]+B[2]<=--.<=A[2]+B[n]. --. 表n: A[n]+B[1]<=A[n]+B[2]<=--..<=A[n]+B[n] 这n张表都是有序的,所以可以以多路归并的思想求出其中前n个最小的元素.对

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

uva 11997 (基础数据结构)

题意: 有一个k*k 的方阵,让你从当中每一行挑选一个数字相加最后能得到K^K次方的和,输出其中最小的k个. 思路:先对每一行排序然后两两归并,每次取前k个再和下一行再进行归并.在归并的时候用一个优先队列维护最大的k个值每次先放k个进去然后一次每行和队顶比较,若是小则替换否则break最后输出即可. 代码如下: 1 #include <stdio.h> 2 #include <algorithm> 3 #include <iostream> 4 #include <

UVA 11997 The K smallest Sums

给出K*K的矩阵,每一行取一个数,构成K个数的和,总共有 k^k种可能,从中取出前k个最小的. 一开始犯了错,因为只要对每行排序,最小的必定是第一列的和,然后我当时就想着,逐步推进,每次将某行的那个数变成其下一列那个数,当然间距要最小.我这样明显是不对的,这样的话每个数只用了一次,而题目的意思明显是可以重复多次. 然后大白上说的是把他看成两行,即每次处理两行,留下最小的k个 再与下一次读入的那一行继续处理.这个方法相当给力,不过有个难点是,怎么在两行的时候,比较快的得到前k小的,我试过全部算一遍