UVA 11997 K Smallest Sums(优先队列)
题意:
给你一个整数K,并且给你K组数,每组K个数,现在在每组中任取一个数,然后相加可以得到一个"和",这样的和共有K^K个.要你输出所有可能和值中最小的那K个。
分析:
刘汝佳:训练指南P189例题.
问题1:如果只有A,B,C三个大小为K的数组,我们如何求"和"能获得最小的前K个和呢?
我们只需要将A和B数组求出前K小的和(第K+1小到之后的所有和值我们都不用管,因为后面压根用到这些值),然后用这个和数组去同样与C数组求出前K小的和即可。如果有K个这样的数组,我们依然用A1与A2求前K小的和,然后用和数组与A3再求和,然后用结果再继续同样与A4求和,与A5求和...等即可。
问题2:A和B两个数组求前K小的和,如何计算能快速得到解呢?
穷举法要K^2的复杂度.这里我们用优先队列来解.因为原本有K^2个可能的和结果。
假设A与B中的数已经排好了序(从小到大),那么前K小的数肯定从下面K个队列中出来(我们等同于将K^2个和分成了K个队列,且每个队列中的元素都是从小到大排列):
队列1: A[1]+B[1] , A[1]+B[2] , … , A[1]+B[K]
队列2: A[2]+B[1] , A[2]+B[2] , … , A[2]+B[K]
队列3: A[3]+B[1] , A[3]+B[2] , … , A[3]+B[K]
队列4: A[4]+B[1] , A[4]+B[2] , … , A[4]+B[K]
...
队列4: A[K]+B[1] , A[K]+B[2] , … , A[K]+B[K]
且每个队列中队首元素肯定是当前最小的候选和之一.所以我们每次从上述K个队列中的K个队首元素里找出最小的那个作为一个前K小的和(每次操作复杂度为logK),连续K次操作可以得到所有前K小的和。
(注意:程序实现只用了一个优先队列priority_queue,此队列中保存了上述K个队列的K个对首元素)
所以我们只需要K^logK复杂度即可求出2个数组组合的前K小数.
综上所述,我们只需要一次构建两个数组的前K小数即可求得最小的前K小数了.
AC代码(新):
#include
#include
#include
using namespace std;
const int maxn = 750+5;
int A[maxn][maxn];
//Node用于构建优先队列的元素
struct Node
{
int sum;//和
int id;//B数组元素下标
Node(int sum,int id):sum(sum),id(id){}
bool operator<(const Node &rhs)const
{
return sum>rhs.sum;
}
};
//将A与B数组的前n小和存入C数组中
void merge(int *A,int *B,int *C,int n)
{
priority_queue Q;
for(int i=0;i
AC代码:
#include
#include
#include
#include
using namespace std;
const int maxn=1000;
int a[maxn],b[maxn];
int k;
struct node
{
int va;//A数组的值
int id;//B数组的元素序号
bool operator<(const node&rs)const
{
return va+b[id]>rs.va+b[rs.id];
}
};
void merge(int *a,int *b,int *c)
{
priority_queue pq;
for(int i=0;i
你可能感兴趣的:(need,to,review,practice,again,ACM--题解汇总,数据结构--STL应用,★★,ACM算法竞赛入门经典题解)