K路归并问题
k路归并:即给定N个有序的序列,要求把这N个有序的序列合并成一个有序的序列。
【问题描述】
有两个长度为 N 的序列 A 和 B,在 A 和 B 中各任取一个数橡胶可以得到
N2 个和,求这N2 个和中最小的 N个。
【文件输入】
第一行输入一个正整数N;第二行N个整数Ai 且Ai≤109;第三行N个整数Bi,
且Bi≤109
。
【文件输出】
输出仅一行,包含 n 个整数,从小到大输出这 N个最小的和,相邻数字之间用
空格隔开。
【样例输入】
5 1 3 2 4 5
6 3 4 1 7
【样例输出】
2 3 4 4 5
【数据规模】
对于 50%的数据,满足 1≤N≤1000;
对于 100%的数据,满足 1≤N≤100000。
分析:
• 数据很大,但是只要求求出前N个,所以可以想到用堆优化
每个表的元素都是从左到右移入新表
• 把每个表的当前元素放入二叉堆中, 每次删除最小值并放入新表中, 然后加入此序列的下一个元素
• 每次操作需要logk时间, 因此总共需要nlogk的时间
• 可以把这些和看成n个有序表:
– A[1]+B[1] <= A[1]+B[2] <= A[1]+B[3] <=…
– A[2]+B[1] <= A[2]+B[2] <= A[2]+B[3] <=…
–…
– A[n]+B[1] <= A[n]+B[2] <= A[n]+B[3] <=…
综上所述,可以采用K路归并:
下面给出代码:
#include <fstream>
#include <cstring>
using namespace std;
ifstream cin("sequence.in");
ofstream cout("sequence.out");
struct
{
int q,num,c;
}e[100001];
int a[100001],b[100001];
void heap(int l,int r)
{
int t;
t=l*2;
while (t<=r)
{
if (t<r&&e[t].c>e[t+1].c) t++;
if (e[t].c<e[t>>1].c)
{
swap(e[t].c,e[t>>1].c);
swap(e[t].num,e[t>>1].num);
swap(e[t].q,e[t>>1].q);
t=t*2;
}else break;
}
}
void qsort1(int l,int r)
{
int i=l,j=r,x=a[(l+r)>>1];
do
{
while (a[i]<x) i++;
while (a[j]>x) j--;
if (i<=j) swap(a[i++],a[j--]);
}while (i<=j);
if (i<r) qsort1(i,r);
if (j>l) qsort1(l,j);
}
void qsort2(int l,int r)
{
int i=l,j=r,x=b[(l+r)>>1];
do
{
while (b[i]<x) i++;
while (b[j]>x) j--;
if (i<=j) swap(b[i++],b[j--]);
}while (i<=j);
if (i<r) qsort2(i,r);
if (j>l) qsort2(l,j);
}
int main()
{
int n,m;
cin>>n;
int i;
for (i=1;i<=n;i++)
cin>>a[i];
for (i=1;i<=n;i++)
cin>>b[i];
qsort1(1,n);
qsort2(1,n);
for (i=1;i<=n;i++)
{
e[i].q=i;
e[i].num=1;
e[i].c=a[i]+b[1];
}
for (i=n>>1;i>0;i--)
heap(i,n);
int tot;
tot=1;
m=n;
while (tot<=m)
{
cout<<e[1].c<<" ";
(e[1].num++);
e[1].c=a[e[1].q]+b[e[1].num];
heap(1,n);
tot++;
}
cout<<endl;
return 0;
}