**
航电oj:Max Sum Plus Plus
**
#题目描述
#大意是 先给你两个数 段数 数字总数 再在数字中找到段数个数字段落 每个数字段落的和要最大
#每个段落的开始结束之间没有其他段落的开始 每个数值最多只能在一个段落里
#知识点
动态规划
#代码
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<stdio.h>
#define maxn 1000007
using namespace std;
int n,m;
int dp[maxn],num[maxn],pre[maxn];
int main()
{
while(scanf("%d%d",&m,&n)!=EOF)
{
memset(dp,0,sizeof(dp));
memset(num,0,sizeof(num));
memset(pre,0,sizeof(pre));
for(int i=1;i<=n;i++)
cin >> num[i];
int temp = -maxn;
for(int i=1;i<=m;i++)//dp[i][j] 表示在标识为j之前 有i段 这个的最大值
{
temp = -0x3f3f3f3f;//重置 一轮就要换 因为这只表示一轮的 每一轮都不同
for(int j=i;j<=n;j++)// j要大于等于i 因为每一个边界都不能相交
{
dp[j] = max(dp[j-1]+num[j],pre[j-1]+num[j]);//这是简化 不减化就超存了
//!! 前者 也为dp[i][j-1]+num[j] 表示num[j] 就在最后的一组中
//!! 后者 也为 max(dp[i-1][j])+num[j] 表示最后的num[j-1]自成一组 max(dp[i-1][j]) 表示上一组 序号在j之前[1~j-1]的最大的值
//!! 虽然 max(dp[i-1][j])可以用循环来找 但会增加o(n)的复杂度 就超时了
pre[j-1] = temp;//1 —— j-1 中间的最大的值
temp = max(temp,dp[j]);// 更新 下一位的前面要将现在这一位包括
}
}
cout << temp <<endl;
}
return 0;
}
#总结
刚刚看觉得还简单 后来越看越难 弄了好久还没怎么太懂 多读读别的大佬的
先找递推函数 1 前一位的可以表示后一位的值 2 前一组的值可以表示后一组的值
参考
https://blog.youkuaiyun.com/codeswarrior/article/details/80310401?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522162194302616780264052271%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=162194302616780264052271&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduend~default-1-80310401.first_rank_v2_pc_rank_v29&utm_term=Max+Sum+Plus+Plus&spm=1018.2226.3001.4187