• 扑克游戏【堆】


    题目大意:
    这里写图片描述
    Input

    3
    5 10 13

    Output

    43

    思路:

    1.贪心

    贪心的过程有点乱。为了让答案平均,我将所有的牌放在树的相邻两层之间,起到平均的作用。将大数放在上,小数放在下,求最小值。
    但是这样是错误的。
    比如说这组数据:
    Input

    4
    10 1 1 1

    正确答案:

    18

    贪心答案:

    26

    (当然我们年级WYC大佬用贪心过了这个样例,但是究竟还是WA了)

    代码被吃了。


    思路二:DFS

    可以用DFS求出每一种可能方案,再在其中求出最小值。

    这样做最然不会WA,但是有个叫做TLE的东西会跑出来烦你。
    这里写图片描述

    代码还没被吃:

    额,那个o数组有点难解释,反正DFS不对,就不解释了。

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    
    const int p=17;
    const int inf=999999999;
    int a[100001],n,m,ans,t,o[21],sum;
    
    void dfs(int x,int k)
    {
        if (!x)   //搜索完了
        {
            if (ans>k) ans=k;
            return;
        }
        for (int i=1;i<=t;i++)
        {
            if (k+i*a[x]>=ans) break;  //(没用的)剪枝
            if (sum>=o[i])
            {
                sum-=o[i];
                dfs(x-1,k+i*a[x]);  //往下搜
                sum+=o[i];
            }
        }
        return;
    }
    
    void csh()  //初始化o数组
    {
        o[p]=1;
        for (int i=p-1;i>=1;i--) 
         o[i]=o[i+1]*2; 
        sum=2*o[1];
        ans=inf;
    }
    
    void init()
    {
        scanf("%d",&n);
        t=(int)log2((double)n-0.0000001)+2;  
        for (int i=1;i<=n;i++)
          scanf("%d",&a[i]);
        sort(a+1,a+1+n);
    }
    
    int main()
    {
        csh();
        init();
        dfs(n,0);
        printf("%d\n",ans);
        return 0;
    }

    正解:合并果子

    不信?把你合并果子AC代码交这一道题试一下?输入输出都不用改!

    思路三:堆

    合并果子的原理相信大家都知道了,在这里解释一下为是么这道题会是合并果子。

    对于一棵树(样例)
    这里写图片描述
    我们用合并果子的方法将它根节点求出。
    这里写图片描述
    那么这时的答案是 28+15=43,正是正确答案。

    那么为什么会是正确答案呢?

    我们将43分解一下。

    43=28+15
    =(13+15)+(10+5)
    =(13+(10+5))+(10+5)
    =13+10+5+10+5
    =13×1+10×2+5×2

    再回到题目给出的图案上
    这里写图片描述
    就会发现,13,10,5所乘的数字正好是它在树的层数!(题目说了根节点为0层)

    所以,这道题与合并果子完全一样!


    代码:

    //与合并果子完全一样,就不解释了
    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cmath>
    using namespace std;
    
    const int inf=99999999;
    int n,a[10001],x,y,sum,m,p,d;
    
    void up(int x)
    {
        while(x>1&&a[x]<a[x/2])
        {
            swap(a[x],a[x/2]);  
            x/=2;
        }
    }
    
    void down(int x)
    {
         int y=x*2;
         while ((y<=n&&a[y]<a[x])||(y+1<=n&&a[y+1]<=a[x]))
         {
            if (a[y]>a[y+1]) y++;
            swap(a[y],a[x]);
            x=y; 
            y=x*2;
         }
    }
    
    int main()
    {
        scanf("%d",&n);
        for (int i=1;i<=n;i++)
        { 
            scanf("%d",&a[i]);
            up(i);
        }
        while(n>1)
        {
            d=a[1]; 
            a[1]=a[n]; 
            n--; 
            down(1);
            d+=a[1]; 
            a[1]=a[n]; 
            n--; 
            down(1);
            n++; 
            a[n]=d; 
            sum+=d; 
            up(n);
        }
        printf("%d\n",sum);
        return 0;
    }
  • 相关阅读:
    lnmp一键安装包,安装多版本php,并开启redis与swoole
    wangEditor的使用
    记一次傻逼的录入
    PHP自动加载
    pip升级
    Ubuntu安装mycli,让mysql命令行可以自动提示
    Redis存储AccessToken
    微信小程序生成太阳码
    巧妙的新订单提醒功能
    使用pt-query-digest进行日志分析
  • 原文地址:https://www.cnblogs.com/hello-tomorrow/p/9313049.html
Copyright © 2020-2023  润新知