您的位置:首页 > 理论基础 > 数据结构算法

数据结构——最大值最小化 (划分子序列)

2014-10-31 23:44 211 查看
第一次写博客,就把第一篇文章给今天在sicily上刷的--最大值最小化

先上题:

把一个包含n个正整数的序列划分成m个连续的子序列(每个正整数恰好属于一个序列)。设第i个序列的各数之和为S(i),如何让所有S(i)的最大值尽量小?

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

n≤106,所有数之和不超过109。

Input

There may be multiple cases.

The first line of the input gives two integer n and m. The next line contains n integers.

Output

For each case, output the minimum value.

Sample Input

Copy sample input to clipboard

6 3

1 2 3 2 5 4

Sample Output

7

//目标学会用猜数字(二分)的方法,换个角度来解决问题
/*我们用二分查找的办法,查找范围是[数组的最大值(max),数组的和(sum)],
* 在这个范围里面的元素x(二分查找用mid表示),
* 能否使m个连续子序列所有的s(i)均不超过x,则该命题成立的最小的x即为答案。
* 该命题不难判断,只需贪心,每次尽量从左向右尽量多划分元素即可。
* (我们把该问题转化为递归分治问题,类似于二分查找。)
* 首先取Sum和元素最大值的中值x,
* 如果命题(judge)为假(就是说当子序列的最大值为x不能把数组分成m段),那么答案比x大;
* 如果命题(judge)为真(就是说当子序列的最大值为x能把数组分成m段),则答案小于等于x。
* 问题得解,复杂度为O(n*logSum)
*/
#include <iostream>
using namespace std;

int array[2000000];

int b_search(int a[], int low, int high, int n, int m);//
bool judge(int a[], int mid, int n, int m);//是否能把序列划分为每个序列之和不大于mid的m个子序列

int main() {
int n;
while (cin >> n) {
int m;
cin >> m;

int sum = 0, max = -1;
for (int i = 0; i < n; i++) {
cin >> array[i];
sum += array[i];
if (array[i] > max)
max = array[i];
}

cout << b_search(array, max, sum, n, m) << endl;
}

return 0;
}

int b_search(int a[], int low, int high, int n, int m) {
while (low < high) {
int mid = (low + high) / 2;

if (judge(a, mid, n, m)) {//能把序列划分为每个序列之和不大于mid的m个子序列,
high = mid;           //为求子序列最大值最小化,范围缩小为[low,mid],
} else {          //不能把序列划分为每个序列之和不大于mid的m个子序列
low = mid + 1;//为求子序列最大值最小化,范围缩小为[mid+1,high]
}
}
return low;  //此时low==high
}

bool judge(int a[], int mid, int n, int m) {
//每次往右划分,划分完后,所用的划分线不大于m-1个即可  ,用k记录划分的段落数
int sum = 0, k = 0;
for (int i = 0; i < n; i++) {
sum += a[i];
if (sum > mid) {//当子序列的和超过假定的最大值mid时,划分
k++;        //增加一条划分线
sum = a[i]; //sum从划分线的下一个元素开始计算
}
}
if (k < m)  //(当子序列的最大值为mid时,可以实现划分)实际划分线<=m-1
return true;
else        //mid太小了,不能划分
return false;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: