一些前言:
据说动态规划会用排序,数据结构来进行乱搞优化操作
动态规划滴核心是个啥呢?状态表示和状态转移
设状态:哪些因素会影响到最终答案,就把哪些因素用数组的维度表示出来
要充分描述,也要简洁
举个例子
计算从(1,1)走到(x,y)的方案数:
走到任意一个(p,q),只能从(p-1,q)和(p,q-1)走过来
那dp[x][y]=dp[x-1][y]+dp[x][y-1]
例一:
最长上升子序列
这个比较简单
dp[i]表示以a[i]为结尾的最长上升子序列的长度
dp[i]=max{dp[j]}+1(a[j]<a[i]&&j<i)
复杂度O(n2)
更秀一点的O(nlogn)做法:
len记录当前的最长上升子序列的长度,d[i]记录当前找到的最长上升子序列的第i项,若a[now]≤d[len],则找到第一个d[j]>a[now]的j,令d[j]=a[now],否则len++,d[len]=a[now],最后的len是最终答案,但d数组不一定是真正的最长上升子序列
dp[i][j]表示前i个位置用j个乘号的最大值
cnt(i,j)表示原数字串第i个数字到第j个数字所组成的数
dp[i][j]=max(dp[i][j],dp[k][j-1]*cnt(k+1,i))
挂饰:
看起来像个贪心(大雾)
那就排个序
按照Ai从大到小排
why?
因为挂钩越多,能挂的东西就越多
dp[i][j]=max(dp[i-1][j],dp[i-1][max(j-a[i],0)+1]+b[i])
蓝字部分是挂第i个挂钩的喜悦值
看蓝字部分的第二维,为什么+1要写在外面呢?
①:当j-a[i]+1<0时,j-a[i]肯定小于0,这时候考虑j-a[i]+1的状态是没有意义的,直接考虑手机上只有一个挂钩的情况
②:当j-a[i]+1==0时,那说明挂上i,就没有挂钩了,并且挂i只需要一个挂钩,也就是说之前手机上只有一个挂钩。如果我们写成max(j-a[i]+1,0),此时是转移到之前手机上没有挂钩的状态,是不对滴。
综上,+1要写在外面
最终答案:max{dp[n][i]}(0≤i≤n)
#include<iostream> #include<cstdio> #include<cmath> #include<algorithm> #include<cstring> using namespace std; inline int read() { char ch=getchar(); int x=0;bool f=0; while(ch<'0'||ch>'9') { if(ch=='-')f=1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return f?-x:x; } int n,dp[2010][2010]; struct G{ int a,b; }g[2010]; bool cmp(G x,G y) { return x.a>y.a; } int main() { n=read(); for(int i=1;i<=n;i++) g[i].a=read(),g[i].b=read(); sort(g+1,g+1+n,cmp); memset(dp,0xcf,sizeof(dp)); dp[0][1]=0;dp[0][0]=0; for(int i=1;i<=n;i++) { for(int j=0;j<=n;j++) { dp[i][j]=max(dp[i-1][j],dp[i-1][max(j-g[i].a,0)+1]+g[i].b); } } int ans=0xcfcfcfcf; for(int i=0;i<=n;i++) ans=max(ans,dp[n][i]); printf("%d",ans); }