【动态规划】最小m段和问题

算法实现题 3-10 最小m段和问题
 
 
问题描述:
给定 n 个整数组成的序列,现在要求将序列分割为 m 段,每段子序列中的数在原序列中 连续排列。如何分割才能使这 m 段子序列的和的最大值达到最小?
 
编程任务:
给定 n 个整数组成的序列,编程计算该序列的最优 m 段分割,使 m 段子序列的和的最大值达到最小。
 
数据输入:
由文件 input.txt 提供输入数据。文件的第 1 行中有 2 个正整数 n 和 m。正整数 n 是序列的长度;正整数 m 是分割的断数。接下来的一行中有 n 个整数。
 
结果输出:
程序运行结束时,将计算结果输出到文件 output.txt 中。文件的第 1 行中的数是计算出的 m 段子序列的和的最大值的最小值。
 
输入文件示例1
 
1 1
10

输出文件示例1

10

输入文件示例2

5 3
1 2 3 4 5

输出文件示例  2 

6

参考以下文章:

https://blog.csdn.net/qq_38367681/article/details/81252798

https://blog.csdn.net/dms2017/article/details/89607379

https://www.cnblogs.com/ljy-endl/p/11610549.html  界面好看

用dp[i][j]存储长度为i,分j段后其子序列和的最大值的最小值,那么它由两部分构成:

                  当j=1时,dp[i][1]表示的是长为i的整个序列的和;

                  当j>1时,dp[i][j] = MIN(for(k=1; k<=i; k++)  MAX(dp[k][j-1], dp[i][1] - dp[k][1]));

这当中k表示的是分段的最后一段子序列的开始下标,所以dp[k][j-1]是前面j-1段子序列和的最大值的最小值,dp[i][1] - dp[k][1]是最后一段子序列的和。所以取这两段中的最大值,在k值变化过程中取得到的最小值就OK了。

 

#include<bits/stdc++.h>
using namespace std;

int dp[1005][1005];
int a[1005];

int main() {
	int n,m;
	cin>>n>>m;
	for(int i=1; i<=n; i++) {
		cin>>a[i];
	}
	for(int i=1; i<=n; i++)
		dp[i][1]=dp[i-1][1]+a[i];
	//dp[i][1]表示分成1段时,最大值
//用dp[i][j]存储长度为i,分j段后其子序列和的最大值的最小值	
	for(int i=1; i<=n; i++) {//枚举长度 
		for(int j=2; j<=m; j++) {//枚举分段数 
			int min=9999;
			for(int k=1; k<=i; k++) {//最后一段的每一次的分组情况
				int t=max(dp[k][j-1],dp[i][1]-dp[k][1]);
				if(t<min) //寻找最小值并赋值
					min=t;
			}
			dp[i][j]=min;
		}
	}
	cout<<dp[n][m]<<endl;
	return 0;
}
/*
5 3
1 2 3 4 5
6
*/


 

#include<bits/stdc++.h>
using namespace std;

int dp[1005][1005];
int sum[1005][1005];
int a[1005];

int main() {
	int n,m;
	cin>>n>>m;
	for(int i=1; i<=n; i++) {
		cin>>a[i];
	}
	for(int i=1; i<=n; i++)
		for(int j=1; j<=m; j++)
			dp[i][j]=9999;//dp都要预先默认一个较大的值 
			
	for(int i=1; i<=n; i++) {
		int num=0;
		for(int j=i; j<=n; j++) {
			num=num+a[j];
			sum[i][j]=num;//sum数组存储第i到第j之间j-i+1个数字之和 
		}
		dp[i][1]=sum[1][i];
	}
	for(int i=2; i<=n; i++) {
		for(int j=2; j<=i&&j<=m; j++) {
			for(int k=1; k<i; k++) {
				dp[i][j]=min(dp[i][j],max(dp[k][j-1],sum[k+1][i]));
			}
		}
	}
	cout<<dp[n][m]<<endl;

	return 0;
}

 

 

 

 

 

  • 4
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

摆烂.MVP

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值