控制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; }