营救
题目描述
一座摩天大楼起了大火,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的莫名其妙的,如果有大佬看出要点的话,欢迎在评论区留言!