最大值最小问题

问题:把一个包含n个正整数的序列划分成m个连续的子序列(每个正整数恰好属于一个序列)。设第i个序列的各数之和为S(i),现在的问题是使得所有的S(i)的最大值尽量小。

数据:1 2 3 2 5 4

划分为3个序列的最优方案为1 2 3 | 2 5 | 4,其中S(1)、S(2)、S(3)分别为6、7、4,最大值为7;如果划分成1 2| 3 2 | 5 4,则最大值为9,不如刚才的好。

分析:给定序列后,我们可以知道任意划分的最大值的取值范围[0, sum(1...n)],一种较慢的方法是枚举每种取值情况,根据枚举值进行序列划分,若划分的组数大于m,说明没有满足条件的划分情况,需要增加枚举值;如果划分的组数小于m,说明找到了满足条件的划分情况。时间复杂度为O(n*sum);

思路扩展:既然找到了线性的枚举方法,我们不妨考虑下二分枚举的方法,考虑mid的情况是否满足条件,如何划分组数大于m,与线性枚举的情况相同;若划分的组数小于m,说明当前解满足条件,但可能还有比当前解还小的解,需进一步计算。

代码如下

#include <stdio.h>
#include <string.h>

int main(void)
{
	int i;
	int n, m;
	int *arr;
	while (scanf("%d%d", &n, &m) != EOF)
	{
		arr = new int[n];
		int sum = 0;
		for (i = 0; i < n; i++)
		{
			scanf("%d", &arr[i]);
			sum += arr[i];
		}
		int left = arr[0];
		int right = sum;
		int mid;
		while (left < right)
		{
			mid = (left + right) / 2;
			int cnt = 1;
			int subsum = 0;
			for (i = 0; i < n; i++)
			{
				if (subsum + arr[i] > mid)
				{
					subsum = arr[i];
					cnt++;
				}
				else
					subsum += arr[i];
			}
			if (cnt > m)
				left = mid + 1;
			else
				right = mid;
		}
		printf("%d\n", left);
		int SubSum = 0;
		for (i = 0; i < n; i++)
		{
			if (SubSum + arr[i] > left)
			{
				SubSum  = arr[i];
				printf("| ");
			}
			else
				SubSum += arr[i];
			printf("%d ", arr[i]);
		}

		delete [] arr;
	}

	return 0;
}

/*
6 3
1 2 3 2 5 4

*/


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值