蓝桥杯每日一练——搬走要石(二分法) python

问题描述
  住在有顶天的天人Tensi对自己的住处很不满。终于有一天她决定把门前碍眼的要石通通丢掉(怒扔要石)。控制要石自然是很容易的事,不过也会消耗灵力。假设搬走一块质量为1的要石会消耗1点灵力,而且由于要石都是连着放置的缘故所以每次除了搬走一颗,也可以搬走连续的任意数量的要石,自然质量是算在一起的。现在Tensi准备最多使用M次灵力,但是她太懒……所以每次只会使用同量的灵力,也因为她太烂,所以也不愿意多花一点灵力……现在很懒的Tensi需要你帮她计算最少一次需要消耗多少灵力,能够在M次内把所有要石都丢到人间去……
输入格式
  第一行两个数N,M,用一个空格分隔。1<=n<=1000,1<=m<=400
  表示一共有N颗要石需要搬走已经Tensi最多发动M次灵力。   接下来包括N 个正整数 0<=ai<=40000
  顺序表示每一颗要石的质量。
输出格式   
   输出一个数T   
  表示Tensi 每次至少消耗T灵力。0<=T<=1000000
  如果无解输出-1.
样例输入
5 3
1 2 1 1 1
样例输出
3
数据规模和约定
  对于100%的数据,1<=n<=1000,1<=m<=400,0<=ai<=40000。   
  保证0<=T<=1000000。

def fun(x):
    count = 1
    sum = 0
    i = 0
    while i < len(stone):   # 用i循环来捡石头
        sum += stone[i]     # 捡起一块石头
        # 如果这是最后一块石头,并且捡的起来(力气够),那就返回真
        if i == len(stone) - 1 and sum <= x:  
            return True
        if sum > x:         # 如果sum > x,也就是力气不够
            sum = 0         # 那就只能把前面的先扔下去了
            count += 1      # 次数+1
            i -= 1          # 既然力气不够,第i块只能重新捡起来,i-1就是把i循环退回到捡不起来的那颗
        elif sum == x:      # 如果力气刚好够
            sum = 0         # 那就把手上的都扔下去
            count += 1      # 次数+1
        if count > m:       # 次数超了
            return False    # 返回假
        # if count == m and i != len(stone) - 1:
        #     return False
        i += 1              # i循环日常 +1


n, m = map(int, input().split())
stone = list(map(int, input().split()))
l = 0         # 左
# 题意可知,答案 不能小于 所有石头重量/次数,再小就完不成任务
for i in stone:
    l += i
l //= m
# 二分法的精髓就是 左和右不断缩小,直到相同
r = 1000000   # 右
min = 0       # 答案
# 开始!
while l < r:
    mid = (l + r) // 2  # 二分法常规操作  取中间数
    if fun(mid):        #判断是否能搬完石头
        r = mid - 1     # 可以的话,右缩小
        min = mid       # 把这个可以的值赋值给min
    else:
        l = mid + 1     # 不行就左边缩小咯
if min == 0:            # 根据题意,min=0  就是没有解,输出-1
    print(-1)
# 这个算法很奇怪(应该是我写的有问题),右的值不一样会出现计算出来的结果不一样,
#有时候会比答案高1,所以用这个蠢办法,测试-1成不成立
elif fun(min - 1):      
    print(min - 1)
else:
    print(min)

看完代码,可能你会问我,为什么不用for循环,因为用不了啊,for循环是不能在循环里边改变i的值的,就算变了,也只是这次循环变了,下次循环还是那个数,所以这里只能用while循环

这道题会有一个误导,每次只会使用同量的灵力,会让考生误以为每一次都必须使用这么多的灵力,少一点都不行,但其实只是不能多于这个数而已,
比如:
5 3
16 14 13 15 10
答案:27
分成三次拿取:16 (14+13) (15+10)
三次都不会高于27,所以答案为27

下面是我一开始以为必须每次使用相同的灵力写的代码:

    count = 0
    for i in range(len(stone)):
        count += stone[i]
        if count == x:
            count = 0
        if count > x:
            return False
        if i == len(stone) - 1 and count != 0:
            return False
        if i == len(stone) - 1 and count == 0:
            return True
n,m = map(int,input().split())
stone = list(map(int,input().split()))
l = 0
for i in stone:
    l += i
l //= m
while l < 10000:
    if fun(l):
        print(l)
        break
    l += 1
  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值