首页 > 试题广场 >

最优分割

[编程题]最优分割
  • 热度指数:2798 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 64M,其他语言128M
  • 算法知识视频讲解
依次给出n个正整数A1,A2,… ,An,将这n个数分割成m段,每一段内的所有数的和记为这一段的权重, m段权重的最大值记为本次分割的权重。问所有分割方案中分割权重的最小值是多少?

输入描述:
第一行依次给出正整数n,m,单空格切分;(n <= 10000, m <= 10000, m <= n)
第二行依次给出n个正整数单空格切分A1,A2,… ,An (Ai <= 10000)


输出描述:
分割权重的最小值
示例1

输入

5 3
1 4 2 3 5

输出

5

说明

分割成 1  4 |   2   3  |   5  的时候,3段的权重都是5,得到分割权重的最小值。
importjava.util.Scanner;
publicclassMain {
    publicstaticvoidmain(String[] args) {
        Scanner n =newScanner(System.in);
        intnum1 = n.nextInt();//5
        intnum2 = n.nextInt();//3
        intnum3 =0;
        if(num1%num2 ==0){
            num3 = num1/num2;
        }else{
            num3 = num1/num2 +1;
        }
        Scanner n2 =newScanner(System.in);
        String[] s = n2.nextLine().split(" ");
        int[] mu =newint[num1];
        for(inti =0;i<num1;i++){
            mu[i] = Integer.parseInt(s[i]);
        }
        int[] minnum =newint[num2];
        inti1 =0;
        inti2 = i1 + num3;
        inttemp =0;
        for(inti =0;i<3;i++){
            if(i2 < num1){
                for(intj = i1;j<i2;j++){
                    temp += mu[j];
                }
                minnum[i] = temp;
                temp =0;
                i1 = i2;
                i2 = i1 + num3;
            }else{
                temp =0;
                for(intk = i1;k < num1;k++){
                    temp += mu[k];
                }
                minnum[i] = temp;
            }
 
        }
        intminnumber =0;
        for(inti =0;i<num2;i++){
             
            for(intj = i+1;j<num2;j++){
                if(minnum[i]<=minnum[j]){
                    minnumber = minnum[i];
                }else{
                    minnumber = minnum[j];
                }
            }
        }
        System.out.print(minnumber);
    }
}
发表于 2019-09-06 00:34:24 回复(1)
// 结果在(max(nums),sum(nums))之间,使用二分查找
// 以[7,2,5,10,8]举例,开始假设只有一个子数组,set=1 
// 第一个 mid = (10+32)/2=21, 然后把数字一个一个塞进去 
// 先塞7, 7<21, 7+2<21, 7+2+5<21, 直到 7+2+5+10>21
// 意味着一个数组放不下, set+1=2, 然后把后面的塞完
// 如果比m大说明我们开的子数组太多, 也就意味值我们数组容量(mid)太小 
// 所以我们就从[22,32]区间中找, 否则在[10,21]中找  


import java.util.Scanner;
public class Main {
    public static int splitArray(int[] nums, int m) {
        int max = Integer.MIN_VALUE, sum = 0;
        for (int i : nums){
            sum += i;
            max = Math.max(max,i);
        }
        
        int left = max, right = sum;
        int mid, set, cur;
        while(left < right){
            mid = (left+right)/2;
            // m 是子数组数,不是cut数
            set = 1;
            cur = 0;
            for(int i : nums){
                if(cur+i > mid){
                    set++;
                    cur = 0;
                }
                cur+= i;
            }
            if(set > m) left = mid + 1;
            else right = mid;
        }
        return left;
    }
    
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();
        int[] nums = new int[n];
        for (int i=0; i<n; i++){
            nums[i] = sc.nextInt();
        }
        System.out.print(splitArray(nums,m));
    }
} 

编辑于 2019-04-13 17:07:54 回复(0)