UVA-11997多路归并问题(K个有序表的合并) K个最小和

K Smallest Sums

两表合并的步骤:
比如说
A序列: 3 6 7
B序列 :6 7 10
表1: 3+6,3+7,3+10
表2:6+6 ,6+7,6+10
表3:7+6,7+7, 7+10
先将3+6,6+6,7+6推进优先队列,然后挑出最小值,并以此为节点向后拓展一个。重复进行。

时间复杂度:优先队列中始终只有n个元素,并且取了n次最小值(拓展了n次)又有(n-1)合并,整体时间复杂度为O(n^2log(n))

#include<stdio.h>
#include<iostream>
#include<cmath>
#include<math.h>
#include<string>
#include<string.h>
#include<algorithm>
#include<stack>
#include<queue>
#include<vector>
#include<map>
#define ms0(a) memset(a,0,sizeof(a))
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
int n,A[800][800];
struct Node{
    int sum,b;
    Node(int sum,int b):sum(sum),b(b){}
    bool operator<(const Node& a) const{
        return sum>a.sum;
    }
};

priority_queue<Node> pq;

void merge(int* A,int* B,int* C,int n)
{
    for(int i=1;i<=n;i++)
    {
        pq.push(Node(A[i]+B[1],1));
    }
    for(int i=1;i<=n;i++)
    {
        Node item = pq.top();pq.pop();
        C[i]=item.sum;
        int b =item.b;
        pq.push(Node(item.sum+B[b+1]-B[b],b+1));
        
    }

}


int main(){
    while (~scanf("%d",&n))
    {

        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                scanf("%d",&A[i][j]);
            }
            sort(A[i]+1, A[i]+n+1);
        }
        for(int i=2;i<=n;i++)
        {
        //每次合并前的队列应该为空。
            while (pq.size()) {
                pq.pop();
            }
            merge(A[1],A[i],A[1],n);
        }
        for(int i=1;i<=n-1;i++)
            printf("%d ",A[1][i]);
        printf("%d\n",A[1][n]);
    }
    return 0;
}

最后回答一下刘老师的思考题:merge(A[1],A[i],A[1],n);这里对A[1]又读又写,会有问题吗?
当然不会(否则就不这样写了),原因在于,改变A[1]中的元素,在这次合并中无影响,因为结构体Node里压根没存A[]的相关信息,自然不影响。

发布了67 篇原创文章 · 获赞 0 · 访问量 1490

猜你喜欢

转载自blog.csdn.net/qq_44846324/article/details/104617019