zoukankan      html  css  js  c++  java
  • 题解 P4379 【[USACO18OPEN]Lemonade Line】

    不敢快速排序又想要快排的速度,还不用STL的小伙伴们看这里!
    小金羊终于学会了堆排以外的另外的一种排序 (打个题解巩固一下)

    归并排序(mergesort):

    时间复杂度和快排一样的优秀。
    先说归并排序的实现:
    首先我们一样的是要进行分解,以达到(O(logn))の时间复杂度。
    然后我们需要了解一下它的思想:

    如果两个序列的顺序已经排好,于是我们合并两个序列。

    emmm...由于分解到最后只有一个元素,一定满足性质。
    然后合并?玄学?这咋合并?
    其实比较简单。
    我们取两个指针,分别指向分解的序列的两个头部,然后比较指针指向的两个元素,满足的就放进我们的辅助空间,直到有一个序列已经用完。
    所以如果剩下的序列如何处置?
    刚刚说了,两个序列都是有序的,如果剩下的都不满足比原先的元素满足性质(大或者小,或者结构体之类的),那么剩下的就依次都放进去就好了。
    没看懂?模拟一下。
    首先序列w[10086],表示奶牛想等的时间,假设6头,序列情况如下:
    (假设从小到大的顺序

    //一开始
    int w={6,2,3,4,5,1};
    //分解第一次
    w1={6,2,3},w2={4,5,1};
    //分解第二次
    w11={6}/*这个好了*/,w12={2,3},w21={4}/*这个也好了*/,w22={5,1};
    //分解最后一次,已经分解完毕的不显示
    w121={2},w122={3},w221={5},w222={1};
    //所以现在序列是
    w11={6},w121={2},w122={3},w21={4},w221={5},w222={1};
    //接下来合并最后分解的那一拨
    w11={6},w12_ok={2,3},w21={4},w22_ok={1/*来自w222*/,5};
    //continue the merge
    w1_ok={2,3,6/*比较到6剩下了,就放进来*/},;
    w2_ok={1/*来自w22_ok*/,4/*来自w21*/,5/*from w22_ok*/};
    //finally
    w_ok={1/*from w2_ok*/,2/*from w1_ok...省略剩下的注释*/,3,4,5,6};
    

    这就是归并排序的步骤。看看代码?
    (仅仅是从小到大的mergesort样例模板代码)Code:

    void mergesort(int l,int r)
    {
        if (l==r)return;//已经只剩一个元素
        int mid=(l+r)>>1;//中部元素
        mergesort(l,mid);//分解左边
        mergesort(mid+1,r);//分解右边
        int s2[r-l+1]/*辅助空间*/,p1=l,p2=mid+1,p3=1;
        while (p1<=mid&&p2<=r)//没分解完
        {
            if (w[p1]<=w[p2])s2[p3++]=w[p1++];
            else s2[p3++]=w[p2++];//以上两行是把较小的放进辅助空间
        }
        while (p1<=mid)s2[p3++]=w[p1++];//若有剩余,放进去
        while (p2<=r)s2[p3++]=w[p2++];//若有剩余,放进去
        p3=l;
        for (register int i=1;i<=r-l+1;i++)
            w[p3++]=s2[i];//再把排好的序列覆盖回去
    }
    

    看看这个题:

    贪心策略:

    先把最愿意排队的奶牛放前面,这样最不愿意排队的奶牛都吃草去了,保证队伍最小。
    上代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    
    using namespace std;
    int w[100001],num,cnt=0;
    void mergesort(int l,int r)
    {
        if (l==r)return;//已经只剩一个元素
        int mid=(l+r)>>1;//中部元素
        mergesort(l,mid);//分解左边
        mergesort(mid+1,r);//分解右边
        int s2[r-l+1]/*辅助空间*/,p1=l,p2=mid+1,p3=1;
        while (p1<=mid&&p2<=r)//没分解完
        {
            if (w[p1]>=w[p2])s2[p3++]=w[p1++];
            else s2[p3++]=w[p2++];//以上两行是把较小的放进辅助空间
        }
        while (p1<=mid)s2[p3++]=w[p1++];//若有剩余,放进去
        while (p2<=r)s2[p3++]=w[p2++];//若有剩余,放进去
        p3=l;
        for (register int i=1;i<=r-l+1;i++)
            w[p3++]=s2[i];//再把排好的序列覆盖回去
    }
    int main()
    {
        scanf("%d",&num);
        for (register int i=1;i<=num;i++)
            scanf("%d",&w[i]);
        mergesort(1,num);
        for (register int i=1;i<=num;i++)
        {
            if (w[i]<cnt)break;
            cnt++;
    	}
    	printf("%d",cnt);
        return 0;
    }
    

    最后提醒大家一点:

    归并排序的辅助空间需求特别大,如是特别要求或者数据范围特别大,请小心使用。

  • 相关阅读:
    链接服务器创建
    线性RAM地址非线性映射转换充分应用RAM地址空间TFT液晶驱动
    FPGA跨时钟域同步,亚稳态等
    Go常见的坑
    VSCode+PicGo+Gitee实现高效markdown图床
    友链
    linux 命令行使用codeql
    Linux 多进程服务配置 systemd
    列表中重复元素的个数
    起不出来题目了呜呜
  • 原文地址:https://www.cnblogs.com/jelly123/p/10392037.html
Copyright © 2011-2022 走看看