bzoj 4247: 挂饰

控制DP按照自己的想法路线转移,之前好像接触过这样一道题目

汉诺塔:通过另一个数组来改变DP方向 和这个有些类似吧

https://www.cnblogs.com/lxy8584099/p/10166796.html

/**************************************************************
    Problem: 4247
    User: lxy8584099
    Language: C++
    Result: Accepted
    Time:3756 ms
    Memory:17252 kb
****************************************************************/
 
/*
 
    首先想到 f i,j表示前i个挂饰 剩下j个空挂钩 的最大喜悦值
        f i,j =max { f i-1,j ; f i-1,j-ai+1 + bi } 
    不过如果全部挂饰都是n个挂钩就得n^3爆炸
    饭后搜题解发现 DP数组可以重新定义一下 
     f i,j表示 前i个挂饰,还剩j个挂钩 的最大喜悦值 
    这里 j那一维的数组开n就够了 因为剩下最多j个挂饰来挂 
    所以这里我们假设上一次即f i-1 只剩下了j个挂钩 
    实际上可能会有多的 不过我们舍去 ,
    多余的空位不影响剩下挂钩对答案的贡献 
        则 f i,j =max{ f i-1,j ; f i-1,max(0,j-a[i])+1 + b[i] }
    想一想 如果 j-a[i]<0 说明本次我们把多余的挂钩舍去了
    这时候为了保证转态按照我们的假设转移,数组初始化负无穷,
    初始化 f 0,1 = 0 表示最开始的1个挂钩 
    试着带一层for循环 发现只有 f 1,1~e[i].a 被"合法"更新了 
    其他的更新都不是 f 0,1转移过来的 所以都是负无穷 
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=2050;
struct pp{int a,b;}e[N];
bool cmpa(pp a,pp b) {return a.a>b.a;}
int n,f[N][N],res;
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d%d",&e[i].a,&e[i].b);
    sort(e+1,e+n+1,cmpa);
    memset(f,~0x3f,sizeof(f));
    f[0][1]=0;
    for(int i=1;i<=n;i++)
        for(int j=0;j<=n;j++)
            f[i][j]=max(f[i-1][j],f[i-1][max(0,j-e[i].a)+1]+e[i].b);
    for(int i=0;i<=n;i++) res=max(res,f[n][i]);
    printf("%d\n",res);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/lxy8584099/p/10685671.html