第二天更新:pre[]数组相当于存的上一次(第一维是i-1)的状态中的最大值
https://vjudge.net/problem/HDU-1024#author=SDUProgramming
下次看到重新看看注释
把一个数组分成m段, sum(i1, j1) + sum(i2, j2) + sum(i3, j3) + … + sum(im,
jm),求使得上述和最大,ik,jk是连续的jk和ik+1可以不连续
动态规划,d[i][j]表示在选取第j个数字的情况下,将前j个数字分成i组的最大和, 则它的值有两种可能
①(x1,y1),(x2,y2)…(xi,yi,num[j])
②(x1,y1),(x2,y2)…(xi-1,yi-1),…,(num[j]),其中yi-1是第k个数字
故:d[i][j]=max(d[i][j-1],d[i-1][k])+num[j],其中k=i-1,i,…,j-1
参考:https://blog.youkuaiyun.com/pmt123456/article/details/52695470
原题(hdu1024)
东东每个学期都会去寝室接受扫楼的任务,并清点每个寝室的人数。
每个寝室里面有ai个人(1<=i<=n)。从第i到第j个宿舍一共有sum(i,j)=a[i]+…+a[j]个人
这让宿管阿姨非常开心,并且让东东扫楼m次,每一次数第i到第j个宿舍sum(i,j) 问题是要找到sum(i1, j1) + … +
sum(im,jm)的最大值。且ix <= iy <=jx和ix <= jy <=jx的情况是不被允许的。也就是说m段都不能相交。 注:1
≤ i ≤ n ≤ 1e6 , -32768 ≤ ai ≤ 32767 人数可以为负数。。。。(1<=n<=1000000)
本来觉得自己比较聪明,然而发现还是太笨了。
实在做不出来,答案也好不容易看的有点懂了
只能笨鸟先飞,多分析点这种不会的题目,然后记住了
明天重做
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <vector>
using namespace std;
const int MAXN_try = 100 + 5;
const int MAXN = 1e6 + 5;
int n, m;
int dp_try[MAXN_try][MAXN_try]; //第j个人放在第i组时候的最大值
int dp[MAXN];
int a[MAXN];
int pre[MAXN];
int pre_try[MAXN_try][MAXN_try];
int k;
//未优化
void solve() {
memset(dp_try, 0, sizeof(dp_try));
for (int i = 1; i <= m; i++) { //区间数
for (int j = i; j <= n; j++) {
int temp = -0x3f3f3f3f;
for (int k = i - 1; k <= j - 1; k++) {
temp = max(temp, dp_try[i - 1][k]);
//temp数据保存到数组pre[],用的时候直接用pre[j-1]
//pre[j] = max(pre[j-1],dp_try[i-1][j])
}
dp_try[i][j] = max(temp + a[j], dp_try[i][j - 1] + a[j]); //dp_try[i][j] = max(temp + a[j], dp_try[i-1][j - 1] + a[j]);
}
}
}
//只使用pre_try[][]数组优化时间,未使用滚动数组优化空间
int solve_1() {
int temp = -0x3f3f3f3f;
memset(dp_try, 0, sizeof(dp_try));
memset(pre_try, 0, sizeof(pre_try));
for (int i = 1; i <= m; i++) {
temp = -1e6; //
for (int j = i; j <= n; j++) {
dp_try[i][j] = max(dp_try[i][j - 1] + a[j], pre_try[i - 1][j - 1] + a[j]);
// // pre_try[i - 1][j - 1]
// 等同于 for (int k = i - 1; k <= j - 1; k++) {
// max(temp, dp_try[i - 1][k]);}
pre_try[i][j - 1] = temp;
temp = max(dp_try[i][j], temp);
}
}
return temp;
}
//正式解
int solve_fast() {
memset(dp, 0, sizeof(dp));
memset(pre, 0, sizeof(pre)); //这里必须有
int tmp = -0x3f3f3f3f;
for (int i = 1; i <= m; i++) {
//隐隐约约懂了。pre[]数组实际相当于一个二维数组pre[i][j]
//第一维相当于利用滚动数组省略了(第一维一直等于i-1)
tmp = -0x3f3f3f3f; //用-1e6会导致错误答案
for (int j = i; j <= n; j++) {
//酝酿不出来了
//参考下https://blog.youkuaiyun.com/pmt123456/article/details/52695470借点思路
//不过有个问题,pre[]不是维护的i-1到j-1范围的最小值?只有一维怎么维护状态?
//沉思中……
dp[j] = max(pre[j - 1] + a[j], dp[j - 1] + a[j]); //pre[j-1]相当于pre[i-1][j-1];
pre[j - 1] = tmp;
tmp = max(tmp, dp[j]);
/*
相当于:
dp[i][j] = max(pre[i - 1][j - 1] + a[j], dp[i - 1][j - 1] + a[j]);
pre[i][j - 1] = tmp; //必须放这里,实现滚动数组
tmp = max(tmp,dp[i][j]);//相当于j个元素分成i个子段字段和的最大值
*/
/*
tmp = max(tmp, dp[j]);
pre[j] = tmp;这么写存在问题
*/
}
}
return tmp;
}
int main() {
#ifdef LOCAL
freopen("zz_in.txt", "r", stdin);
freopen("zz_op.txt", "w", stdout);
#endif
while (~scanf("%d %d", &m, &n)) {
// scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
// solve();
// cout << dp_try[m][n] << endl;//这样写不对(最大解不一定包含最后一个元素)
// cout << solve_1() << endl;
cout << solve_fast() << endl;
// cout << dp[n] << endl; //fault
}
//int t, i, j, k;
//cin>>t;
//while(t--)
//{
//}
#ifdef LOCAL
printf("Time used = %.2f\n", (double) clock() / CLOCKS_PER_SEC);
#endif
return 0;
}
第二天更新:
不够自信啊,return位置写错了导致WA(弱智bug),结果却怀疑自己dp写错了;编译器都有警告也没看到
关键还是理解的不算特别透彻啊
下次继续,mmp,不信了
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <vector>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAXN = 1e6 + 5;
int n, m;
int dp[MAXN];
int pre[MAXN];
int a[MAXN];
int solve() {
int tmp = -INF;
memset(dp, 0, sizeof(dp));
memset(pre, 0, sizeof(pre));
for (int i = 1; i <= m; i++) {
tmp = -INF;
for (int j = i; j <= n; j++) {
dp[j] = max(dp[j - 1] + a[j], pre[j - 1] + a[j]);
pre[j - 1] = tmp;
tmp = max(tmp, dp[j]);
}
}
return tmp; //return错了位置导致报错……
}
int main() {
#ifdef LOCAL
freopen("zz_in.txt", "r", stdin);
freopen("zz_op.txt", "w", stdout);
#endif
while (~scanf("%d %d", &m, &n)) {
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
cout << solve() << endl;
}
#ifdef LOCAL
printf("Time used = %.2f\n", (double) clock() / CLOCKS_PER_SEC);
#endif
return 0;
}