算法实现题3-8最小m段和问题
问题描述:给定n个整数组成的序列,现在要求将序列分割为m段,每段子序列中的数在原序列中连续排列。如何分割才能使这m段子序列的和的最大值达到最小?
算法设计:给定n个整数组成的序列,计算该序列的最优m段分割,使m段子序列的和的最大值达到最小。
数据输入:第1行中有2个正整数n和m。正整数n是序列的长度;正整数m是分割的段数。接下来的一行中有n个整数。
输入样例:
样例1:
1 1
10
样例2:
5 3
5 4 3 2 1
结果输出:第1行中的数是计算出的m段子序列的和的最大值的最小值。
输出样例:
样例1:
10
样例2:
6
样例2解析:
给定序列:5 4 3 2 1 n=5, m=3 可分为 5 | 4 | 3 2 1 其子序列和的最大值的最小值为1+2+3=6。
算法设计:
用c[i][j]存储长度为i,分j段后其子序列和的最大值的最小值,那么它由两部分构成:
当j=1时,c[i][1]=c[i-1][1]+a[i]表示的是长为i的整个序列的和;
当j>1时,c[i][j] = min(for(k=1; k<=i; k++)max(c[k][j-1], c[i][1] - c[k][1]));
其中,k表示的是分段的最后一段子序列的开始下标
c[k][j-1]是前面j-1段子序列和的最大值的最小值
c[i][1]是整个序列的和,c[k][1]是前k个序列的和,c[i][1] - c[k][1]是最后一段子序列的和
最终取这两段中的最大值的最小值。
AC码:
#include<bits/stdc++.h>
using namespace std;
int c[100][100]; //存储0~i的j个分组的和的最大值的最小值
int M(int a[],int n,int m)
{
for(int i=1;i<=n;i++) //j=1即只有1段,计算整个序列的和
{
c[i][1]=c[i-1][1]+a[i];
}
for(int i=1;i<=n;i++)
{
for(int j=2;j<=m;j++)
{
int min=99999,t;
for(int k=1;k<i;k++) //k表示分开的位置
{
t=max(c[k][j-1],c[i][1]-c[k][1]);
if(t<min)
min=t;
}
c[i][j]=min;
}
}
return c[n][m];
}
int main()
{
int n,m;
cin >> n >> m;
int a[100];
for(int i=1;i<=n;i++)
{
cin >> a[i];
}
M(a,n,m);
cout << c[n][m];
return 0;
}