UVA11997 K Smallest Sums

题目

一句话题意 , 有 k 个长为 k 的序列 , 从其中每个序列选一个数 (k^k) 个和中输出前k小

考虑 有两个长为n的序列 , 从他们中选出(n)最小的和 , 可以用一个很妙的想法

在优先队列里 , 存((a_1 + b_1 , 1) , (a_2 + b_1 , 1) , (a_3 + b_1 , 1) dots)

第一个是 a+b , 第二项是b的下标 , 每次取出最小的 , 然后把 (x - b[id] + b[id] + 1) 放进去(b 是排好序的)

取 n 遍就行, 而有 k 个的序列的情况两两合并就可以了,正确性贪心可证 ,不写了。。。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
const int N = 756;
int n;
int a[N] , b[N];
priority_queue< pair<int,int> , vector< pair<int,int> > , greater< pair<int,int> > > q; 
void Merge()
{
	while(q.size()) q.pop();
	for(int i = 1 ; i <= n ; ++i) q.push(make_pair(a[i] + b[1] , 1));
	int tot = 0;
	while(q.size())
	{
		int x = q.top().first , y = q.top().second; q.pop();
		a[++tot] = x; if(tot == n) break; 
		if(y < n) q.push(make_pair(x - b[y] + b[y+1] , y+1));
	}
	return ;
}

int main()
{
	while(scanf("%d" , &n) == 1)
	{
		for(int i = 1 ; i <= n ; ++i) scanf("%d",&a[i]); // 这里要先读进去一遍a , 不然直接合并就是 n 个 0 与 b 合并 
		for(int j = 2 ; j <= n ; ++j)
		{
			for(int i = 1 ; i <= n ; ++i) scanf("%d",&b[i]);
			sort(b + 1 , b + 1 + n);
			Merge();
		}
		printf("%d",a[1]);
		for(int i = 2 ; i <= n ; ++i) printf(" %d" , a[i]); puts("");
	}
	return 0;
}
原文地址:https://www.cnblogs.com/R-Q-R-Q/p/12154607.html