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;
    }
    

    最后提醒大家一点:

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

  • 相关阅读:
    jQuery EasyUI API 中文文档 可调整尺寸
    jQuery EasyUI API 中文文档 链接按钮(LinkButton)
    jQuery EasyUI API 中文文档 手风琴(Accordion)
    jQuery EasyUI API 中文文档 表单(Form)
    jQuery EasyUI API 中文文档 组合(Combo)
    jQuery EasyUI API 中文文档 布局(Layout)
    jQuery EasyUI API 中文文档 拆分按钮(SplitButton)
    jQuery EasyUI API 中文文档 菜单按钮(MenuButton)
    jQuery EasyUI API 中文文档 搜索框
    jQuery EasyUI API 中文文档 验证框(ValidateBox)
  • 原文地址:https://www.cnblogs.com/jelly123/p/10392037.html
Copyright © 2011-2022 走看看