最小M段和问题

本文探讨了最小M段和问题,即如何将一串数字分割成M段,使各段和的最大值最小。通过动态规划算法,文章详细介绍了递推方程dp[i][j]=min(max{dp[i][1]-dp[k][1],dp[k][j-1]}

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最小M段和问题:

  • 问题描述:

给定n个整数组成的序列,现在要求将序列分割成m段,每段子序列中的数在原数列中连续排列。如何分割才能使m段子序列的和的最大值达到最小?

  • 数据输入:

第一行中有2个正整数n和m。正整数n是序列的长度,正整数m是分割的段数。接下来的一行中有n个整数。

  • 算法思想:

使用dp[i][j]放置将前i个数分成j段的最大最小值。
所以dp[i][1]就是前i个数的和,dp[i][1] = dp[i-1][1] + a[i];
当j>1的时候,假设前k个数为j-1段,从k~i为第j段,所以前j-1段的最大最小值为:dp[k][j-1] (前k个数分为j-1段).
最后一段为:dp[i][1]-dp[k][1] (前i个数的和减去前k个数的和)
这两个值中选取一个最大值,当所有情况讨论结束后,选出结果中最小的作为dp[i][j]的值。

  • 递推方程:
    dp[i][j] = min(max{dp[i][1]- dp[k][1],dp[k][j-1]})

在这里插入图片描述
代码:

package DongTaiGuiHua;
/*
 * 递推方程:
 * dp[i][j] = min(max{dp[i][1]- dp[k][1],dp[k][j-1]})
 * */

import java.util.Scanner;

public class 最小m段和问题 {
	public static int a[] = new int[100]; // 存放输入的n位整数
	public static int dp[][] = new int[1024][1024]; // dp中存放长度从1到n的所有划分结果的最大最小值,最后一个求得的dp[i][j]放置将i个数分成j段的最大最小值。。
	
	public static void main(String[] args) {
		int n, m, maxvalue = 0;
		Scanner input = new Scanner(System.in);
		n = input.nextInt();// 输入整数位数n
		m = input.nextInt();// 输入划分个数m
		
		for(int i = 1; i <= n; i++) {
			a[i] = input.nextInt();// 输入n位等待划分的正整数
		}
		for(int i = 1; i <= n; i++) {
			dp[i][1] = dp[i-1][1] + a[i];// dp[i][1]就是前i个数的和
		}
		
		for(int i = 1; i <= n; i++) {
			for(int j = 2; j <= m; j++){
			// 把i位整数划分成j段
				int minvalue = 99999; // 保存最小值用,要保存最小值就需要初始化成一个极大值
				for (int k = j - 1; k < i; k++) { 
					// K是划分位置,只用k划分成两段,因为划分得到的前半部分都是讨论过的。
					int temp = Max(dp[i][1] - dp[k][1], dp[k][j-1]);
					// 前j-1段的最大最小值为:dp[k][j-1];(前k个数划分成j-1段)
					// 最后一段为:dp[i][1] - dp[k][1] ;(前i个数的和减去前K个数的和)
					if(temp < minvalue) {
						minvalue  = temp; // 保存最小值
					}
				}
				dp[i][j] = minvalue; // 把所有k情况下的最小值赋值给dp[i][j]。
			}
		}
		System.out.println(dp[n][m]);
	}
	
	public static int Max(int a, int b) {
		if (a > b) {
			return a;
		}else {
			return b;
		}
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值