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;
}
q记录的是组别,num记录的是组中的元素取到的个数。

posted @ 2010-11-06 16:59  forever zsz  阅读(1564)  评论(0编辑  收藏  举报