最小m段和问题(动态规划)

本文探讨了最小m段和问题,即如何将一个整数序列分割为m段,使得各段和的最大值最小。文章详细阐述了最优子问题的概念,提出了状态转移方程,并给出了具体实现算法,最后分析了时间复杂度。

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

最小m段和问题

1.问题描述:

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

2.最优子问题:

把前 i 个数据划分成 j 段(i>=j),最优划分中的前 j-1 段的最后一个数据是k号(k>=j-1),必然有:这前 j-1段就是前 k 个数据的最优 j-1划分。

3.状态转移方程:

t [i] [j] 表示前 i 个数据划分成 j 段的子段和中的最大值,且这个最大值是所有划分方案中最小的。

t [i] [j] = min(j<=k<=i) { max(t [k] [j-1] , ∑(k<=x<=i)ax ) }

4.实现:

M[i][j]记录前i个数据划分成j段的最优划分方法中的最后一段的左端点。

时间复杂度:O(mn^2)

int solve(int a[],int n,int m){
	int i,j,k,t[n+1][m+1],M[n+1][m+1],sum,getMax;
	//初始化  
	for(i=0;i<=n;i++)//其他 
		for(j=0;j<=m;j++)
			t[i][j]=M[i][j]=MaxInt;
	t[0][0]=M[0][0]=0;//0段&&0数据
	 
	for(j=1;j<=m;j++){//划分成1~m段 
		for(i=j;i<=n;i++){//用j~n个数据 
			sum=0;//i个数据划分成j段。第j段的和 
			for(k=i;k>=j;k--){//第j段的左端点 
				sum+=a[k-1];
				getMax=max(t[k-1][j-1],sum);
				if(getMax<t[i][j] ){
					t[i][j]=getMax;
					M[i][j]=k;//记录划分点 
				}
			}
		} 
	}
	
	//输出
	i=n;j=m,k=m-1;
	int mark[m+1];
	while(i>=1&&j>=1){
		mark[k]=M[i][j];
		i=mark[k]-1;
		k--;j--;
	} 
	mark[m]=n+1;
	
	i=1;k=0;
	while(i<=n){
		cout<<"{";
		for(;i<mark[k+1];i++){
			cout<<a[i-1]<<' ';
		}
		cout<<"}";
		k++;
	}
	cout<<"\n";
	return t[n][m];
} 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

hnu哈哈

请接受直女的么么哒????

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

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

打赏作者

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

抵扣说明:

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

余额充值