最大值最小化

来源:互联网 发布:java 所有数据类型 编辑:程序博客网 时间:2024/04/30 01:46
/* * 算法竞赛入门经典 8.3.5 最大值最小化 * 问题描述:把一个包含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,不是最小。 * 问题分析:能否使m个连续子序列所有的s(i)均不超过x,则该命题成立的最小的x即为答案。该命题不难判断,只需贪心,每次尽量从左 * 向右尽量多划分元素即可。我们把该问题转化为递归分治问题,类似于二分查找。首先取Sum和元素最大值的中值x,如果命题为假,那么答案比x大; * 如果命题为真,则答案小于等于x。问题得解,复杂度为O(n*logSum) * */import java.util.Scanner;public class MaxToMin {int[] arr;int sum;int max;int m;int n;public static void main(String[] args) {Scanner scanner = new Scanner(System.in);MaxToMin mm = new MaxToMin();while((mm.n = scanner.nextInt()) > 0) {mm.arr = new int[mm.n];mm.m = scanner.nextInt();mm.sum = 0;mm.max = 0;for(int i=0; i<mm.n; i++) {mm.arr[i] = scanner.nextInt();mm.sum += mm.arr[i];if(mm.max < mm.arr[i]) mm.max = mm.arr[i];}System.out.println(mm.divide());}}private boolean isDivide(int x) {//能否将序列划分成m个各子序列和不大于x的序列boolean ok = true;int s=0;// 当前划分段的和int count = 0;//计数划分线  不能大于m-1;for(int i=0; i<n; i++) {if(arr[i] > x) {//某个元素值超过x 不能划分 退出ok = false;break;}if(s + arr[i] > x) {//当前元素不能加到该段了count ++;//增加一段s = arr[i];//下一段和if(count > m-1) {//划分段数过多ok = false;break;}}else {s += arr[i];}}return ok;}private int divide() {int x = max, y = sum;while(x < y) {int mid = x + (y-x)/2;if(isDivide(mid)) {y = mid;} else {x = mid+1;}}return x;}}

原创粉丝点击