UVA 11997 K Smallest Sums(优先队列)

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算法竞赛入门经典题解)