序列合并 AC 短代码 题解

本文介绍了一种新颖的方法来解决P1631【序列合并】问题。通过使用heap堆排和优化的空间分配策略,该方法有效地解决了两个有序数组的合并问题,并提供了完整的实现代码。

题解 P1631 【序列合并】

各位,我发现有一种新奇的做法就能解决此题~

39行实测AC代码+思路

先讲思路。

  • 很显然我们有 a和b两个数组 。
  • 很显然我们要用一个 c数组存和 。
  • 很显然要用heap堆排(实际上是只用了向下维护操作)。
  • 我们的c[ i ][ j ],用来存储a中第i个数分别和b中的所有数相加得到的结果。很显然 会 爆空间,所以等下会有优化。
        for (int i = 1;i <= n;i++)
            for (int j = 1;j <= n;j++)
                c[i][j] = a[i]+b[j];//a中第i个数分别和b中的所有数相加得到的结果
  • 依题意得:a是有序数列,b也是有序数列,则对于任意c[ i ]也会是一个有序数列。
  • 那么我们就把c[ i ]的第一个数存入heap。
        for (int i = 1;i <= n;i++)
                heap[i] = c[i][j];  
  • 然后维护一下heap
  • while(没有输出够n个数)
  • {
  • 输出;
  • 放入 堆顶数所在的数组的下一个数(好好咀嚼一下)
  • 维护
  • }

优化

  • 经过arfa同志的提醒,我们发现定义的c数组会爆空间。
  • 于是我们开始了优化之旅。
  • 首先我们知道,heap[ i ]只需要用一个值,那我们可不可以在heap需要的时候再把c[ i ][ j ]算出来呢?
  • 然后我们发现 c[ i ][ j ] = a[ i ]+b[ j ]中i相当于目前对顶数所在的数组,j就表示下一个数的下标。
  • 于是优化就出来了。
    for (int i = 1;i <= n;i++) heap[i] = a[i]+b[1]
     ……
    int t = from[1];
    step[t]++;
    heap[1]=a[t] + b[ step[t] ];
  • 有人可能看不懂。我做一个比喻吧。假如你是拱野驾校隔壁的老王肠粉店店长,因为拱野驾校的学员很多,所以你的生意很红火。但是他们想要各种口味的。你想了一个办法:买来几个碟子,先把各种肠粉都做几份,再卖出去。实际上,你只需要现做现卖的合成就ojbk了。

上代码

#include<bits/stdc++.h>
using namespace std;
int a[100000],b[100000],heap[100000],from[100000],step[100000],n,sum=1;
void swap(int x,int y)//手打swap交换,同时交换来源数组。
{
    int k = heap[x];
    heap[x] = heap[y];
    heap[y] = k;
    k = from[x];
    from[x] = from[y];
    from[y] = k;
}
int main()
{
    scanf("%d",&n);
    for (int i = 1;i <= n;i++) scanf("%d",&a[i]);
    for (int i = 1;i <= n;i++) scanf("%d",&b[i]);
    for (int i = 1;i <= n;i++) heap[i] = a[i]+b[1],from[i] = i,step[i] = 1; 
    //这一步就是优化。把c去掉了,取而代之的是现做现卖的合成。
    while (sum <= n)
    {
        printf("%d ",heap[1]);
        int t = from[1];
        step[t]++;
        heap[1]=a[t] + b[ step[t] ];//现做现卖的合成。
        int x = 1,s;
        while (x<<1 <= n)//经典的下传
        {
            s = x<<1;
            if (heap[s] > heap[s + 1] && s + 1 <= n) s++;
            if (heap[x] > heap[s])
            {
                swap(x,s);
                x = s;  
            }else break;
        }
        sum++;  
    }
    return 0;
}

发表于 2018-04-19 13:25:12 in 题解

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值