POJ2442

Posted bakacirno

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ2442相关的知识,希望对你有一定的参考价值。

题目:http://poj.org/problem?id=2442

题意:给m个包含n个数字的数列,在每个数列中选一个数加起来,这样的和由nm个,求这些和中最小的前n个。

可以先看两个数列的情况,假设这两个数列为A,B。先将这两个数列从小到大排序,那么最小的和肯定是A[1]+B[1],而第二小的就是min(A[2]+B[1],A[1]+B[2]),假设就是A[2]+B[1]吧。那么第三小的就是min(A[2]+B[1],A[3]+B[1],A[1]+B[2]),根据这个规律,我们知道,如果确定A[i]+B[j]是前n个中的一个那么就可以将A[i]+B[j+1]和A[i+1]+B[j]纳入下一个最小值的考虑范围之内。那么我们用优先队列就可以动态的取我们考虑范围内的最小值,从而得出这两个数列前n小和。

如果扩展到m个数列的话,我们可以先求出前2个数列的前n小和,然后利用这个结果和第3个数列,求出前3个数列的前n小和,以此类推,求出m个数列的前n小和。

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <queue>
#define MAXN 2010
using namespace std;
int T,n,m,num1[MAXN],num2[MAXN],num3[MAXN],vis[MAXN][MAXN];
struct Node
    int i,j;
    
    friend bool operator < (const Node &a,const Node &b)
    
        return num1[a.i]+num2[a.j]>num1[b.i]+num2[b.j];
    
;
priority_queue<Node> pq;

int main()

    scanf("%d",&T);
    while(T--)
    
        scanf("%d %d",&m,&n);
        for(int i=1;i<=n;i++) scanf("%d",&num3[i]);
        sort(num3+1,num3+n+1);
        for(int i=2;i<=m;i++)
        
            memset(vis,0,sizeof(vis));
            for(int j=1;j<=n;j++) scanf("%d",&num2[j]);
            sort(num2+1,num2+n+1);
            for(int j=1;j<=n;j++) num1[j]=num3[j];
            while(!pq.empty()) pq.pop();
            pq.push(1,1);
            for(int j=1;j<=n;j++)
            
                int p1=pq.top().i,p2=pq.top().j;
                pq.pop();
                num3[j]=num1[p1]+num2[p2];
                if(p1<n&&!vis[p1+1][p2]) pq.push(p1+1,p2),vis[p1+1][p2]=1;
                if(p2<n&&!vis[p1][p2+1]) pq.push(p1,p2+1),vis[p1][p2+1]=1;
            
        
        for(int i=1;i<=n;i++) printf("%d ",num3[i]);
        printf("\n");
    
    return 0;

 

以上是关于POJ2442的主要内容,如果未能解决你的问题,请参考以下文章

POJ2442

POJ-2442 Sequence(手写堆优化)

poj2442 堆应用

poj 2442 Sequence

poj2442优先队列

《算法竞赛进阶指南》0x17二叉堆 POJ2442 矩阵取数求前N大