TYVJ P1078 删数 Label:区间dp

描述

有N个不同的正整数数x1, x2, ... xN 排成一排,我们可以从左边或右边去掉连续的i个数(只能从两边删除数),1<=i<=n,剩下N-i个数,再把剩下的数按以上操作处理,直到所有的数都被删除为止。
每次操作都有一个操作价值,比如现在要删除从i位置到k位置上的所有的数。操作价值为|xi – xk|*(k-i+1),如果只去掉一个数,操作价值为这个数的值。
任务
如何操作可以得到最大值,求操作的最大价值。 

输入格式

输入文件remove.in 的第一行为一个正整数N,第二行有N个用空格隔开的N个不同的正整数。
3<=N<=100,N个操作数为1..1000 之间的整数。

输出格式

输出文件remove.out 包含一个正整数,为操作的最大值

测试样例1

输入


54 29 196 21 133 118

输出

768

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int a[105],f[105][105],sum[105][105];
int N;

int get_sum(int l,int r){
    if(sum[l][r]>=0) return sum[l][r];
    else{
        int pos=0;
        pos=abs(a[l]-a[r])*(r-l+1);
        return pos;
    }
}

int dp(int l,int r){
    if(l==r) return a[l];
    if(l+1==r){
        int pos=0;
        pos=get_sum(l,r);
        pos=max(pos,a[l]+a[r]);
        return pos;
    }
    if(f[l][r]>=0) return f[l][r];
    for(int k=l+1;k<r;k++){//错误代码
        f[l][r]=max(f[l][r],dp(l,k)      + dp(k+1,r));
        f[l][r]=max(f[l][r],dp(l,k)      + get_sum(k+1,r));
        f[l][r]=max(f[l][r],get_sum(l,k) + dp(k+1,r));
        f[l][r]=max(f[l][r],get_sum(l,k) + get_sum(k+1,r));
    }
    return f[l][r];
}

int main(){
//  freopen("01.txt","r",stdin);
    memset(f,-1,sizeof(f));
    memset(sum,-1,sizeof(sum));
    scanf("%d",&N);
    for(int i=1;i<=N;i++) scanf("%d",&a[i]);
    printf("%d
",dp(1,N));
    return 0;
}

这个代码没有AC,不知道问题何在,有个点没有过。。。(下文已解决

我的想法是不管怎么取,所在区域与第几次取是没有关系的。

于是就4种情况。。。//这句话就留着吧,以后明白自己错在哪里

数据如下:


输入

100
169 36 193 11 80 329 155 421 67 222 106 225 175 100 151 227 117 340 129 19 395 292 308 48 89 310 518 302 460 105 355 33 554 455 233 44 293 6 295 7 161 164 556 435 71 402 221 353 203 311 324 217 520 511 108 26 373 13 95 241 230 162 403 258 365 20 326 8 218 176 206 516 120 351 275 157 350 103 330 204 90 187 451 167 104 418 541 215 349 214 294 426 216 212 420 111 121 424 283 22

输出

51206

补充

找到错误了:上述代码没有考虑只有右边取一个的情况,只要把dp条件中k=l+1改为k=l就可以

这个错误犯了好几次了,刚才思考了一下,应该是这个问题,于是过了

附代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int a[105],f[105][105],sum[105][105];
int N;

int get_sum(int l,int r){
    if(sum[l][r]>=0) return sum[l][r];
    else{
        int pos=0;
        pos=abs(a[l]-a[r])*(r-l+1);
        return pos;
    }
}

int dp(int l,int r){
    if(l==r) return a[l];
    if(l+1==r){
        int pos=0;
        pos=get_sum(l,r);
        pos=max(pos,a[l]+a[r]);
        return pos;
    }
    if(f[l][r]>=0) return f[l][r];
    for(int k=l;k<r;k++){//这里被修改了
        f[l][r]=max(f[l][r],dp(l,k)      + dp(k+1,r));
        f[l][r]=max(f[l][r],dp(l,k)      + get_sum(k+1,r));
        f[l][r]=max(f[l][r],get_sum(l,k) + dp(k+1,r));
        f[l][r]=max(f[l][r],get_sum(l,k) + get_sum(k+1,r));
    }
    return f[l][r];
}

int main(){
//  freopen("01.txt","r",stdin);
    memset(f,-1,sizeof(f));
    memset(sum,-1,sizeof(sum));
    scanf("%d",&N);
    for(int i=1;i<=N;i++) scanf("%d",&a[i]);
    printf("%d
",dp(1,N));
    return 0;
}

 再补充更优代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<algorithm>
 6 using namespace std;
 7 int sum[105][105],f[105][105],a[105],N;
 8 int get_sum(int l,int r){
 9     if(sum[l][r]>=0) return sum[l][r];
10     if(l==r) return sum[l][r]=a[l];
11     else return sum[l][r]=abs(a[l]-a[r])*(r-l+1);
12 }
13 
14 int dp(int l,int r){
15     if(f[l][r]>=0) return f[l][r];
16     f[l][r]=get_sum(l,r);//最开始也类似这样的思路,但是没写这句话,
                //导致没有考虑到一次全删的情况
17 for(int k=l;k<r;k++){ 18 f[l][r]=max(f[l][r], get_sum(l,k) + dp(k+1,r)); 19 f[l][r]=max(f[l][r], dp(l,k) +get_sum(k+1,r)); 20 } 21 return f[l][r]; 22 } 23 24 int main(){ 25 // freopen("01.txt","r",stdin); 26 memset(f,-1,sizeof(f)); 27 memset(sum,-1,sizeof(sum)); 28 29 scanf("%d",&N); 30 for(int i=1;i<=N;i++) scanf("%d",&a[i]); 31 32 printf("%d ",dp(1,N)); 33 return 0; 34 }

片段一:

1 f[l][r]=max(f[l][r],dp(l,k)      + dp(k+1,r));
2 f[l][r]=max(f[l][r],dp(l,k)      + get_sum(k+1,r));
3 f[l][r]=max(f[l][r],get_sum(l,k) + dp(k+1,r));
4 f[l][r]=max(f[l][r],get_sum(l,k) + get_sum(k+1,r));

讲一下存在的问题:

1)dp开始时应该对该状态进行初始化,比如补充代码第十六行(片段二)

片段二:

f[l][r]=get_sum(l,r);//最开始也类似这样的思路,但是没写这句话,
             //导致没有考虑到一次全删的情况

2)片段一第一行代码无用,本来就会考虑到

3)第四行基本上就等同于片段二 ,还绕了个弯

总结起来就是dp应该理解自己要递归什么,然后写完不急调样例,

在脑海中过一遍代码历程,检查是否有状态没有考虑到

再讲一句:sum数组有开45ms,没开60ms

但是如果f数组没开的话就呵呵了

版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 3.0 许可协议。转载请注明出处!
原文地址:https://www.cnblogs.com/radiumlrb/p/5784265.html