最小m子段和问题
题目描述
给定n个整数组成的序列,现在要求将序列分割为m段,每段子序列中的数在原序列中连续排列。 如何分割才能使这m段子序列的和的最大值达到最小?
解题思路
用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]是最后一段子序列的和。
具体代码实现
#include <stdio.h>
#include<stdlib.h>
#define MAX_VALUE 32767
int dp[100][100] ; //dp[i][j]存储0~i的j个分组的和的最大值的最小值
int MAX(int n1,int n2){
if(n1<n2)
return n2 ;
else
return n1 ;
}
void calculate(int a[],int n,int m){
dp[0][1]=0;
for(int i=1;i<=n;i++){ //当j=1时,dp[i][1]表示的是长为i的整个序列的和
dp[i][1] = dp[i-1][1] + a[i] ;
}
for(int i=1;i<=n;i++){
for(int j=2;j<=m;j++){
int min=MAX_VALUE ;
for(int k=1;k<=i;k++){ //最后一段的每一次的分组情况,k表示的是分段的最后一段子序列的开始下标
int temp=MAX(dp[k][j-1],dp[i][1]-dp[k][1]);
if(temp<min){ //寻找最小值并赋值
min=temp ;
}
}
dp[i][j]=min;
}
}
printf("%d",dp[n][m]);
}
void dp_test_printf(int n,int m){
printf("\ndp数组如下:\n");
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
printf("%2d ",dp[i][j]);
}
printf("\n");
}
}
int main(){
int n,m;
printf("请输入数组长度:");
scanf("%d",&n);
int *a=(int *)malloc(sizeof(int)*(n+1));
printf("请输入分段个数:");
scanf("%d",&m);
printf("请输入数组元素:");
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
calculate(a,n,m);
// dp_test_printf(n,m);
return 0;
}