题目链接: vjudge
翻译
题目大意:输入一个m,n分别表示成m组,一共有n个数即将n个数分成m组,m组的和加起来得到最大值并输出。
解题思路:
状态dp[i][j]表示前j个数分成i组的最大值,且最后一个分组一定包含第j个数
动态转移方程:
dp[i][j]=max( dp[i][j-1]+a[j] , dp[i-1][k]) + a[j] (0<k<j)
dp[i][j-1]+a[j]表示的是前j-1个数分成i组,第j个接在前一组的最后。
dp[i-1][k] ) + a[j] 表示的前(0<k<j)分成i-1组,第j个作为下一个组的开头。其中的 k 当 dp[i-1][k] 为最大值时取到。(因为dp[i][j]包含第j个数,所以必须取上一行的最值)
优化思路
思路类似于01背包优化:因为动态转移方程每次更新只使用两行的数据,所以开两个一维dp数组代替二维数组。
本例中使用的是int pre_max[N];
存放上一行 , int dp[N];
存放当前行。
代码
#include <cstring>
#include <iostream>
// 正无穷
#define inf 0x3f3f3f3f
// #define int long long
using namespace std;
int max(int a, int b)
{
if (a > b)
return a;
else
return b;
}
typedef pair<int, int> PII;
const int N = 10 + 1e6;
int dp[N]; //
int a[N];
int pre_max[N]; // 上层区段[i,n]中最大值
int n, m;
void solve()
{
int mx = -inf;
memset(dp, 0, sizeof dp);
memset(pre_max, 0, sizeof pre_max);
for (int i = 1; i <= n; i++)
cin >> a[i];
for (int i = 1; i <= m; i++)
{
mx = -inf;
for (int j = i; j <= n; j++)
{
dp[j] = max(dp[j - 1], pre_max[j - 1]) + a[j]; // 使用上层最值
pre_max[j - 1] = mx; // 为下次迭代更新上层最值
mx = max(dp[j], mx);
// mx 记录当前层[i,j]区段max 用做更新pre_max
}
}
// int ans=-inf;
// for(int i=m;i<=n;i++)//注意起始点
// ans=max(ans,dp[i]);
// cout<<ans<<endl;
cout << mx << endl;
}
int main()
{
ios::sync_with_stdio();
while (cin >> m >> n)
solve();
return 0;
}
代码参考: 链接