多路归并优先队列——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;
}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值