• OJ 21658::Monthly Expense(二分搜索+最小化最大值)


     
     

    Description

    Farmer John是一个令人惊讶的会计学天才,他已经明白了他可能会花光他的钱,这些钱本来是要维持农场每个月的正常运转的。他已经计算了他以后N(1<=N<=100,000)个工作日中每一天的花费moneyi(1<=moneyi<=10,000),他想要为他连续的M(1<=M<=N)个被叫做“清算月”的结帐时期做一个预算,每一个“清算月”包含一个工作日或更多连续的工作日,每一个工作日都仅被包含在一个“清算月”当中。 FJ的目标是安排这些“清算月”,使得每个清算月的花费中最大的那个花费达到最小,从而来决定他的月度支出限制。

    Input

    第一行:两个用空格隔开的整数:N和M

    第2..N+1行:第i+1行包含FJ在他的第i个工作日的花费

    Output

    第一行:能够维持每个月农场正常运转的钱数

    题解:

    M<=N,如果分成<M个清算月满足要求,那么也可以分成M个清算月。

    最大值最小,考虑二分。

    二分一个ans。

    然后模拟一下每一天尽量把钱用完,

    得到一个需要的清算月数目cnt。

    若cnt<=M合法,否则不合法。

    思路:我们可以直到这个值必然在所有数中最大值与所有数的总和之间,那么只要再这个区间进行二分即可

    AC 代码:这是一个可能超时的代码

    #include<stdio.h>
    #include<algorithm>
    using namespace std;
    int n,m;
    int a[100100];
    bool mmp(int mid)
    {
        int sum=0;
        int ans=1;
        for(int i=1;i<=n;i++)
        {
            if(sum+a[i]<=mid)
                sum+=a[i];
            else
            {
                sum=a[i];
                ans++;
            }
        }
        if(ans > m)
            return 0;
    
            return 1;
    }
    int main()
    {
    
        int tail,head,mid;
        while(scanf("%d%d",&n,&m)!=EOF)
        {
            tail=0,head=1;
            for(int i=1;i<=n;i++)
            {
                scanf("%d",&a[i]);
                tail+=a[i];
                head=max(head,a[i]);
            }
    
            mid=(head+tail)/2;
            while(tail>=head)
            {
                if(mmp(mid)==0)
                    head=mid+1;
                else
                    tail=mid-1;
    
                    mid=(head+tail)/2;
            }
            printf("%d
    ",mid+1);
        }
    }
    View Code

    下面这是进行了一些剪支

    #include <iostream>
    #include <cstdio>
    #define maxn 100005
    using namespace std;
    int cost[maxn];
    int n,m;
    bool judge(int x)
    {                      //用来判断按当前二分值作为题目要求的最大值,所分出的堆是否合理。<br>{
        int s=0,t=0;
        for (int i=0;i<n;i++)
        {
            if (cost[i]>x) return false;///高妙之处剪枝
            if (s+cost[i]>x)
            {
                if (t>=m-1) return false;///剪枝
                t++;
                s=cost[i];
            }
            else
            s+=cost[i];
        }
        return true;
    }
    int binary(int maxx,int sum)  //二分部分
    {
        int mid,left=maxx,right=sum;
        while (left<right)
        {
            mid=left+(right-left)/2;
            if (!judge(mid)) left=mid+1;
            else
            right=mid;
        }
        return left;
    }
    int main()
    {
        int maxx=0;//二分的下界
        int sum=0;//二分的上界
        scanf("%d%d",&n,&m);
        for (int i=0;i<n;i++)
        {
            scanf("%d",&cost[i]);
            maxx=max(maxx,cost[i]);
            sum+=cost[i];
        }
        printf("%d
    ",binary(maxx,sum));
        return 0;
    }
    View Code

    题后感:好好学习下什么是最小化最大值与最大化最小值吧

  • 相关阅读:
    文本框设置只读,后台可获取
    div 在同一行的 CSS处理
    在标签中添加属性
    (转)如何使用SignalTap II觀察reg與wire值? (SOC) (Verilog) (Quartus II) (SignalTap II)
    (转)如何使用ModelSim對Megafunction或LPM作仿真? (SOC) (MegaCore) (ModelSim)
    (笔记)TSL235新型光感器件强烈推荐使用
    (转)如何增加SignalTap II能觀察的reg與wire數量? (SOC) (Quartus II) (SignalTap II)
    (转) 如何將10進位轉2進位? (C/C++) (C)
    (转)如何使用ModelSim作前仿真與後仿真? (SOC) (Quartus II) (ModelSim)
    (笔记)关于LM3S片内FLASH编程的一点建议
  • 原文地址:https://www.cnblogs.com/shuaihui520/p/8911147.html
Copyright © 2020-2023  润新知