描述:
有n个整数,分成m段。使每一段的和的最小值尽可能的大。
输入:第一行是两个整数n(整数个数),m(分段数),接下来一行是n个整数
输出:输出尽可能大的每一段和的最小值
样例输入:
5 3
4 2 4 5 1
样例输出:
4
分析:首先这是一个动态规划的算法。所谓动态规划也就是把待求解的问题分成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。区别于分治法,动态规划的子问题往往是相互不独立的,子问题会被重复计算。这样我们可以先保存已解决的子问题,然后在用到的时候再找出已求的答案,这样就能避免重复计算带来的时间上的浪费。
动态规划解法:
(说明:以下所有数组下标皆从1开始,不是从0开始,只为方便理解)
用opt数组来记录计算的结果。opt[a][b]代表a个顶点分成b段所得到最优解,即我们要输出的尽可能大的每一段和的最小值。
首先定义一个初始值opt[0][1] = 0;
1、当分段数 j = 1 时,也就是分一段时,f[i][1] = f[i - 1][1] + temp[i];
其中temp是我们输入的一组数据;
2、当分段数 j >= 2 && j <= m时,f[i][j] = max(min(f[i][1] - f[k][1],f[k][j-1]));
其中 k 是一个中间变量,其值位于 1 与 i - 1之间, 1 < k < i - 1;
i 为数据的个数,即n代表的意义。
下面分享我的代码:C/C++
#include <iostream>
#define myMax(a,b) (((a) > (b)) ? (a) : (b))
#define myMin(a,b) (((a) < (b)) ? (a) : (b))
using namespace std;
int main()
{
int i,j,k,n, m;
int temp[51];
int opt[51][51] = { 0 };
int Min;
int Max = 0;
cin >> n >> m;
for (i = 1; i <= n; i++)
{
cin >> temp[i];
}
// 初始化
opt[0][1] = 0;
// j = 1的情况
for (i = 1; i <= n; i++)
{
opt[i][1] = opt[i - 1][1] + temp[i];
}
Min = opt[n][1];
// j >= 2 ,j组数,i数的个数,k数据的个数
for (j = 2; j <= m; j++)
{
for (i = j; i <= n; i++)
{
Min = 0;
for (k = 1; k <= i - 1 ; k++)
{
Max = myMin(opt[i][1] - opt[k][1], opt[k][j - 1]);
if (Max > Min)
Min = Max;
}
opt[i][j] = Min;
}
}
cout << Min << endl;
return 0;
}