zoukankan      html  css  js  c++  java
  • 蒟篛的P1334 瑞瑞的木板 题解(合并果子也是可以这样做的)

    /*

    本题是一个比较简单的堆排序的题目,

    思想和之前的合并果子非常像(简直一模一样) 我每次找到数列中最小的俩个进行合并,

    再将合并后的数存入数列中 (可以用堆实现,大佬可以无视直接用优先队列,原理是一样的,

    我们建立一个二叉树,让每个子节点都大于它的父亲节点 二叉树的根节点就成了最小值)

    再找新的数列中最小的俩个;

    (以此类推,并将过程中找到的合并后的值加起来就是答案)

    */

    #include<bits/stdc++.h>

    using namespace std;

    int n;

    long long l,s[50000],da;//题目数字给的太大了,不开long long过不了。

    void sf(int wz)//上浮,将一个新值按规矩上移(每个子节点都大于它的父亲节点)

    {

      while(wz!=1)//到顶结束

      {

        int cnm=wz>>1;//位运算,相当于除以2(向下取);

        if(s[wz]<s[cnm])

           swap(s[wz],s[cnm]);

        else//找到自己位置也可以结束

          break;

         wz=cnm;

      }

    }

    void xc()//下沉,将一个较大值按规矩下移(顺便找到新的最小)

    {

      int wz=1;

      while((wz<<1)<=n)

      {

        int cnm=wz<<1;//相当于乘2

         int t=wz;//t表示我当前的值和t的值交换

        if(cnm<=n&&s[wz]>s[cnm])

          t=cnm;//有左边并且可换

        if(s[wz]>s[cnm+1]&&s[cnm]>s[cnm+1]&&cnm+1<=n)

          t=cnm+1;//有右边并且比左边好

        if(t!=wz)//不等交换

          swap(s[wz],s[t]);

         else//找到位置,不动了

          ·break;

         wz=t;

      }

    }

    int main()

    {

      cin>>n;

      for(int i=1;i<=n;i++)

      {

        cin>>l;

        s[i]=l;//表示我新进来一个数,我先暂时把它放在完全二叉树末尾(也就是第i个)

        sf(i);//我要把树中第i个点的数按要求上浮(上小下大)

      }

      for(int i=1;n!=1;i++)//当我节点个数为1时就做完了

      {

        int k=s[1];//取一个最小

        s[1]=s[n--];//将这个最小变为一个较大值

        xc();//把这个较大值下沉(相当于去掉最小,重新找最小)

        k=k+s[1];//再取

        s[1]=s[n--];//再删

        xc();

        s[++n]=k;//将新值存入完全二叉树末尾

        sf(n);//再次上浮

        da=da+k;//累计答案

      }

      cout<<da;

    }

  • 相关阅读:
    线段的平移和旋转
    《构建之法》第一章读书笔记
    课程大作业总结
    2016.1.8
    2016.1.7
    2016.1.6总结
    初学MFC
    实时控制软件第三次编程作业
    实时控制软件设计第二次编程作业
    实时控制软件设计第一次编程作业
  • 原文地址:https://www.cnblogs.com/ren-meng-hua-qi/p/9108637.html
Copyright © 2011-2022 走看看