ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【题解】营救(二分答案)

2022-01-28 17:07:26  阅读:184  来源: 互联网

标签:二分 题解 更新 120 181 179 188 营救 172


营救

题目描述

一座摩天大楼起了大火,n个人都被困在了顶层狭长的走廊上,大家排着长长的队伍等着逃离险境。但火势很猛,消防员升起的救生舱只有m次运人下来的机会,并且每次运的人总重量还不能太重,避免将救生舱压垮。此时如何将这一排人分隔成m个连续的小组,(大家遵守逃生守则,没有人会往前插队),并且让这m个组中总重量最重的那个组的重量尽量小。这样才能快速安全的将大家都救离险境。
现在告诉你这n个人的体重,请你找出一种分组方法,让这m个组中总重量最重的那个组的重量尽量小,并输出这个组的总重量。

输入

第一行两个正整数n和m,中间用一个空格隔开,表示有n个逃生的人和要分隔成m个连续的小组。
第二行n个正整数,每个整数之间用一个空格隔开,表示n个人的体重(单位:公斤)。

输出

一个正整数,表示m个组中总重量最重的那个组的重量。

样例输入

6 3
20 30 50 80 100 120

样例输出

180

提示

一种合理的分法(20 30 50)(80 100)(120)
数据范围:
30% 1<=n<=10;

5<=m<=10;
70% 1<=n<=100;5<=m<=20;
100% 1<=n<=10000; 100<=m<=1000;


思路

二分答案的运用。求最重的那个组的重量,所以二分范围为n个人中的最大体重到总重,得到一个体重x再循环n遍,看在最多承载x重量的情况下分成几组,组数大于等于m就将x往大求,否则将x往小求。

ac代码:

#include <bits/stdc++.h>
using namespace std;
int n,m,c,res,a[10010],l,r,x;
int main()
{
    cin>>n>>m;
    for(int i=0; i<n; i++)
    {
        cin>>a[i];
        r+=a[i];       //右边界,总重
        l=max(l,a[i]); //左边界,最大体重
    }
    while(l<=r)
    {
        x=(l+r)/2;   //取得一个体重x
        res=0;
        c=0;
        for(int i=0; i<n; i++)
        {
            if(res+a[i]<x)
            {
                res+=a[i];//能塞就塞
            }
            else
            {
                res=a[i];
                c++;      //不能塞放下一组,组数加一
            }
        }
        if(c>=m) l=x+1; //大于等于规定组数m,x往大求
        else r=x-1;    //否则x往小求
    }
    cout<<(l+r)/2<<endl;//循环最后更新l,r,不能直接输出x
    return 0;
}

边界的思考

首先,对于题目样例

6 3
20 30 50 80 100 120

初始边界l=120, r=400。

这是每次循环的l, r, x, c

l=120   r=400   x=260   c=1
更新后:l=120   r=259
l=120   r=259   x=189   c=2
更新后:l=120   r=188
l=120   r=188   x=154   c=3
更新后:l=155   r=188
l=155   r=188   x=171   c=3
更新后:l=172   r=188
l=172   r=188   x=180   c=3
更新后:l=181   r=188
l=181   r=188   x=184   c=2
更新后:l=181   r=183
l=181   r=183   x=182   c=2
更新后:l=181   r=181
l=181   r=181   x=181   c=2
更新后:l=181   r=180

有一个问题,20行塞人的语句 res+a[i]<x 如果改成 res+a[i]<=x ,就是加上a[i]刚好等于额定的x,也把a[i]加到那一组,但是得到的结果是179,与答案不符,这次每次循环的l, r, x, c

l=120   r=400   x=260   c=1
更新后:l=120   r=259
l=120   r=259   x=189   c=2
更新后:l=120   r=188
l=120   r=188   x=154   c=3
更新后:l=155   r=188
l=155   r=188   x=171   c=3
更新后:l=172   r=188
l=172   r=188   x=180   c=2
更新后:l=172   r=179
l=172   r=179   x=175   c=3
更新后:l=176   r=179
l=176   r=179   x=177   c=3
更新后:l=178   r=179
l=178   r=179   x=178   c=3
更新后:l=179   r=179
l=179   r=179   x=179   c=3
更新后:l=180   r=179

 从红色段开始不同,研究之后我发现,代码中的c根本不是实际分的组数!而是实际组数-1 !!可是我把c每次初始设为1,塞人语句改为 res+a[i]<=x ,得到的结果是219???心态炸了。。。

凭借自己对二分的认识,我把ac代码中更新l的语句改为 l=x , 条件改while退出为 l<r ,样例能过,但是提交后就tle了。。。

研究了半天还是不知道为啥,看来我对二分的认识还非常非常浅显,这段代码a的莫名其妙的,如果有大佬看出要点的话,欢迎在评论区留言!

标签:二分,题解,更新,120,181,179,188,营救,172
来源: https://blog.csdn.net/m0_60543948/article/details/122724880

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有