📅  最后修改于: 2023-12-03 15:23:02.503000             🧑  作者: Mango
给定一个长度为N(N<=1000)的数组,元素均为正整数,将该数组分成M(M<=N)个非空的连续子数组,每个子数组的元素之和记为该子数组的权值。 定义所有子数组的权值中的最大值为该分割的权值。 找到一种最优的分割方案,使得分割后所有子数组的权值中的最大值最小。
第一行输入n和m,表示数组长度和分割数 第二行输入n个正整数,表示给定数组
输出最小的最大子数组和
输入:
5 3
1 2 3 4 5
输出:
5
这道题是对"贪心"算法的一个经典应用,可以采用二分答案进行求解。
总体思路为将数组的元素二分,每次进行判断,将数组按照划分的策略,划分为连续的子数组,并根据所划分的策略计算所有子数组的权值。如果权值最大的子数组小于等于二分的值,则更新全局最小值,否则就抛弃当前状态,继续二分。
def check(mid):
cnt = 1
cur_sum = 0
for i in range(n):
if(a[i] > mid):
return False
if(cur_sum + a[i] > mid):
cnt += 1
cur_sum = a[i]
else:
cur_sum += a[i]
return cnt <= m
n, m = map(int, input().split())
a = list(map(int, input().split()))
l = 0
r = sum(a)
ans = r
while(l <= r):
mid = (l + r) // 2
if(check(mid)):
ans = min(ans, mid)
r = mid - 1
else:
l = mid + 1
print(ans)
代码分析:
首先得到题目给的输入:
n, m = map(int, input().split())
a = list(map(int, input().split()))
因为我们要用到二分法,需要设置左右边界:
l = 0
r = sum(a)
ans = r
继续进入二分的循环,每一次取中间值,并按照贪心算法的策略进行计算:
while(l <= r):
mid = (l + r) // 2
if(check(mid)):
ans = min(ans, mid)
r = mid - 1
else:
l = mid + 1
check函数用来判断方案是否可行,每次传入一个mid,计算分割后权值中的最大值,如果最大值小于等于mid,则代表方案可行,否则不行。
def check(mid):
cnt = 1
cur_sum = 0
for i in range(n):
if(a[i] > mid):
return False
if(cur_sum + a[i] > mid):
cnt += 1
cur_sum = a[i]
else:
cur_sum += a[i]
return cnt <= m
最后输出结果即可:
print(ans)
至此,本题已经成功解决。