NC600牛牛分蛋糕(二分)

题目陈述

大意:给定两种若干数量的蛋糕和一些盘子,问所有的分法中,蛋糕数量最少的盘子中分到最多的蛋糕数量是多少。所有分法应该满足:同一个盘子不装有两种蛋糕、每个盘子都有蛋糕。

算法一:朴素做法

算法思路

  • 为了不多次重复冗余的文字,接下来我们约定,将蛋糕数量最少的盘子中分到最多的蛋糕数量称为 a n s ans ans
  • 我们先这样分析,如果有 x x x个盘子,只有一种蛋糕,数量为 a a a,那么所有分法的 a n s ans ans就是 a / x a/x a/x
  • 为什么?此处我们感性理解一下,取 a n s ans ans的时候,一定是所有盘子的最大值和最小值的差值是最小的,如果不是最小的,将最大值的几个蛋糕,移动到最小值上面,我们又得到了更大的 a n s ans ans,与我们当初的定义相互矛盾。
  • 我们从 1 − x 1-x 1x依次一个位置一个位置放蛋糕,循环的放置,直至放完位置,这样放置出来的必然是最优情况,此时最大值和最小值的差值至多为 1 1 1,将最大值上面的一个移动到最小值,则完成了互换,即此时最大值和最小值的差值稳定,即无法减小,即最大值和最小值的差值是最小的
  • 这种情况,即我们计算有 x x x个盘子,只有一种蛋糕,数量为 a a a,的 a n s ans ans,按照上面的分法,只需要 x / n x/n x/n即可计算出来 a n s ans ans
  • 那么两种蛋糕如何处理?同理,枚举第一种蛋糕用的盘子 i i i,剩下的 n − i n-i ni种盘子给第二种蛋糕,二者各自的 a n s ans ans再取一个最小值,即可得到该分法的 a n s ans ans
  • i i i线性遍历 [ 1 , n − 1 ] [1,n-1] [1,n1]即可获取所有方案
  • 此处可能有同学想问,是否存在只用一种蛋糕就得到了所有分法的 a n s ans ans?因为题目数据保证了 2 ≤ n ≤ a + b 2\leq n \leq a+b 2na+b,故不存在只有一种蛋糕分法而得到所有分法的 a n s ans ans的情况。

代码实现

class Solution
{
public:
    int splitCake(int n, int a, int b)
    {
        int aAns, bAns, ans = -1;
        //第一种单独的ans,第二种单独的ans,总的ans
        for (int i = 1; i < n; i ++) 
        {
            aAns = a / i; //求解第一种的ans
            bAns = b / (n - i); //求解总的ans 
            if(aAns > 0 && bAns > 0) //两种单独的方法都合法
                ans = max(ans, min(aAns, bAns)); //求解总得ans
        }
        return ans;
    }
};

复杂度分析

  • 时间复杂度,一个for循环从 1 − n 1-n 1n,复杂度为 O ( n ) O(n) O(n)
  • 空间复杂度,定义了变量 a A n s , b A n s , a n s aAns,bAns,ans aAns,bAns,ans,复杂度为 O ( 1 ) O(1) O(1)

算法二:二分法

  • 我们设一种分法中第一种、第二种蛋糕分别占用了 a N u m , b N u m aNum,bNum aNumbNum个盘子,每个盘子内的蛋糕数量分别为 a i ( 1 ≤ i ≤ a N u m ) , b i ( 1 ≤ i ≤ b N u m ) a_i(1\leq i \leq aNum),b_i(1 \leq i \leq bNum) ai(1iaNum),bi(1ibNum)

  • 则有 ∑ a i = a , ∑ b i = b \sum a_i = a,\sum b_i=b ai=a,bi=b

  • a i ≥ a m i n a_i\geq a_{min} aiamin,所以 a i a m i n ≥ 1 \cfrac{a_i}{a_{min}}\geq 1 aminai1则有, a 1 a m i n + a 2 a m i n + . . . + a a N u m a m i n ≥ a a m i n ≥ a N u m \cfrac{a_1}{a_{min}}+\cfrac{a_2}{a_{min}}+...+\cfrac{a_{aNum}}{a_{min}}\geq \cfrac{a}{a_{min}}\geq aNum amina1+amina2+...+aminaaNumaminaaNum

  • 故有 a a m i n ≥ a N u m \cfrac{a}{a_{min}}\geq aNum aminaaNum

  • 故同理有 b b m i n ≥ b N u m \cfrac{b}{b_{min}}\geq bNum bminbbNum

  • 显然最后的 a n s ans ans会取二者中更小的一个,即 a n s = m i n ( a m i n , b m i n ) ans=min(a_{min},b_{min}) ans=min(amin,bmin)

  • 若方案合法则有 a a m i n + b b m i n ≥ a N u m + b N u m = n \cfrac{a}{a_{min}}+ \cfrac{b}{b_{min}}\geq aNum +bNum=n amina+bminbaNum+bNum=n

  • a a m i n + b b m i n ≥ n \cfrac{a}{a_{min}}+ \cfrac{b}{b_{min}}\geq n amina+bminbn

  • 易得 a m i n ( a m i n , b m i n ) + b m i n ( a m i n , b m i n ) ≥ n \cfrac{a}{min(a_{min},b_{min})}+ \cfrac{b}{min(a_{min},b_{min})}\geq n min(amin,bmin)a+min(amin,bmin)bn

  • a a n s + b a n s ≥ n \cfrac{a}{ans}+ \cfrac{b}{ans}\geq n ansa+ansbn

  • 假设此处的 a n s ans ans我们用 i i i来枚举,我们可以知道对于答案有这样一个性质, 1 ≤ i ≤ a n s 1\leq i\leq ans 1ians都是合法方案, a n s < i ≤ n ans<i\leq n ans<in都不合法,如图
    在这里插入图片描述

  • 对于前者(其实题目没有说一定需要放完所有蛋糕),我们将最小值的位置移动一块到最大值的位置即可构造更小的情况

  • 对于后者,反证法,如果 a n s < i ≤ n ans<i\leq n ans<in合法,则与已有条件矛盾,故得证。

  • 即区间具有二段性,可以使用二分法。

  • 此时我们对 a i + b i ≥ n \cfrac{a}{i}+ \cfrac{b}{i}\geq n ia+ibn进行二分答案即可

代码实现

class Solution
{
public:
    int splitCake(int n, int a, int b)
    {
        int l = 1, r = min(a, b), mid; //左边界,右边界,中点
        当a<b,a中无法拿出b个蛋糕来,反之亦然,故右边界需要取小的那个
        while (l < r) //l == r的时候,代表已经找出答案
        {
            mid = (l + r + 1) / 2; //向上取整,避免死循环
            if (check(n, a, b, mid)) //该分法合法,说明可以取更大的值
                l = mid; //左边界缩小
            else //该分法不合法,说明只能取最小的值
                r = mid - 1; //右边界缩小
        }
        return l; //返回答案
    }
    bool check(int &n, int &a, int &b, int x) //二分条件
    {
        return a / x + b / x >= n; //两种蛋糕每盘都分最小的,若合法总和应该不小于n
    }
};

复杂度分析

  • 时间复杂度,为二分答案的复杂度,最多二分 log ⁡ m i n ( a , b ) − 1 \log min(a,b) - 1 logmin(a,b)1次,复杂度为 O ( log ⁡ m i n ( a , b ) ) O(\log min(a,b)) O(logmin(a,b))
  • 空间复杂度,定义了 l , r , m i d l,r,mid l,r,mid,为 O ( 1 ) O(1) O(1)
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值