两表合并的步骤:
比如说
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[]的相关信息,自然不影响。