最优分割

最优分割

牛客网:最优分割
二分法的简单运用
题目描述
依次给出n个正整数A1,A2,… ,An,将这n个数分割成m段,每一段内的所有数的和记为这一段的权重, m段权重的最大值记为本次分割的权重。问所有分割方案中分割权重的最小值是多少?
输入描述:
第一行依次给出正整数n,m,单空格切分;(n <= 10000, m <= 10000, m <= n)
第二行依次给出n个正整数单空格切分A1,A2,… ,An (Ai <= 10000)
输出描述:
分割权重的最小值

示例1
输入

5 3
1 4 2 3 5
输出
5

说明
分割成 1 4 | 2 3 | 5 的时候,3段的权重都是5,得到分割权重的最小值。

思路:

  • 二分逼近法
    • 这个题的意思:假设存在数组 1 4 2 3 5 分割成 3 段,有几种分法呢,答案是 C4^2: 43/21 = 6 种,
    • 即在数组的四个间隔中插入两根柱子将其分成 3 段,每一种分法中会对应有 3 个子数组的值,其中最大的值即为当前分割方法的
    • 最大权值,在所有的分割方法中找出最小的一个最大权值,听起来好像有点绕
    • eg:1 | 4 2 | 3 5 这种分割方法,它的最大权值为 8 而: 1 4 | 2 3 | 5 分割方法,它的最大权值为 5
    • 思路:假设存在一个最大值的最小值 x,反过来划分数组。子数组的权值都比x要小,如果组数小于m,说明 x 还可以再小;
    • 组数大于m,说明 x 需要变大,以容纳更多的数。减小分组数。如果组数等于m,x也可能再小
    • 考虑边界情况,现在把每个元素分成一组,那么x的最小值就是数组中最大的值;把数组当成一个组,那么x就是数组元素之和。
    • 即 max(nums) <= x <= sum(nums)
    • 因为每一组都是连续的,只要每一组累加的和大于了x,那么当前元素就要放到下一组,记录有多少组即可。
    • 我们通过二分逼近来确定这个x的值。
    • 在于这个“逼近”,这道题是在连续的数值范围中逼近,换句话说,每个组的和一定在范围之内,因此正确答案是不会被跳过的;
# -*- coding: utf-8 -*-
def bisearch(arr, m): #参考高赞回复的答案
    left = max(arr)
    right = sum(arr)
    while left < right:
        mid = (left + right)//2
        sets = 1
        cur = 0
        for num in arr:
            if cur + num > mid:
                sets += 1
                cur = 0
            cur += num
        if sets > m:
            left = mid+1
        else:
            right = mid
    return left
if __name__=='__main__':
    n,m = list(map(int,raw_input().split()))
    num = list(map(int,raw_input().split()))
    print(bisearch(num,m))

  • 动态规划法:
  • dp[i][j] 代表前面i个数被分成m个区间的权值
    空间复杂度略高
def dp_array(num,n,m):
    dp = [[float('inf') for _ in range(m+1)] for _ in range(n+1)]
    dp[0][0] = 0
    for i in range(1,n+1):
        for j in range(1,m+1):
            for k in range(i):
                dp[i][j] = min(dp[i][j],max(dp[k][j-1],sum(num[k:i])))
    return dp[n][m]
if __name__=='__main__':
    n,m = list(map(int,raw_input().split()))
    num = list(map(int,raw_input().split()))
    print(dp_array(num,n,m))
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值