BIT 程序设计与实践 22.序列划分

来源:互联网 发布:ch341a编程器软件 编辑:程序博客网 时间:2024/06/06 07:25

BIT 程序设计与实践 22.序列划分

标签(空格分隔): 二分 贪心

22. 序列划分

题目:

给定一个由非负整数组成的序列及正整数 m,将原始的序列划分成 m 个连续的子序列。针对每个划分,计算 m 个子序列中最大和,针对所有可能的划分,找出最小的最大子序列和。如,给定序列为 [7,2,5,10,8] 及划分个数 m = 2,可得到 4 种划分:
1.[7] 和 [2,5,10,8],最大子序列和为 25
2.[7,2] 和 [5,10,8],最大子序列和为 23
3.[7,2,5] 和 [10,8],最大子序列和为 18
4.[7,2,5,10] 和 [8],最大子序列和为 24

因此,可以得出最小的最大序列和为 18。

输入:

第一行输入两个整数 n m,其中 n 代表序列的长度,m 代表划分个数,1 ≤ n ≤ 1000,1 ≤ m ≤ min(50, n)

接下来的一行为序列中的 n 个非负整数(取值范围 0~10000),用空格分隔。

输入:

最小的最大子序列和。

输出样例:

5 2
7 2 5 10 8

期待输出

18

思路:
No.1 二分法
No.2 dp(动态规划);

NO.1

二分最大序列的和
下界low为数组中的最大值;
上届high为数组中各元素的和;
简单二分模板题

记住哦

代码:

#include<stdio.h>#include<string.h>int n,m;int a[10005];int isvalid(int c){int i; int cn=0,counter=1;for(i=0;i<n;i++){    if(a[i]>c)    return 0;    if(cn+a[i]<=c)    {        cn+=a[i];    }    else    {        cn=a[i];        counter++;    }}if(counter>m)return 0;else return 1;}int main(){int i;scanf("%d%d",&n,&m);int low,high,mid;high=0;low=0;for(i=0;i<n;i++){    scanf("%d",&a[i]);    if(a[i]>low)    low=a[i];    high+=a[i];}mid=(high+low)/2;while(high-low>5)//重点{    if(isvalid(mid))    {        high=mid-1;    }    else    {        low=mid+1;    }    mid=(high+low)/2;}for(i=0;i<=5;i++){    if(isvalid(low+i))    {    printf("%d\n",low+i);    break;    }}return 0;} 

重点

二分循环的跳出条件
不应是high-low>0
因为题中已经认定全为非负整数
可以让high-low>n(较小整数)跳出循环后
依次判定low到high这个区间段内的整数是否符合isvalid
(注意从low开始增加,要求最小的最大子序列)