结合ycx讲的几个例题,分析一下闫式DP的具体应用方法。
AcWing 2. 01背包问题
for(int i=1;i<=n;i++)
{
for(int j=1;j<=v;j++)
///以上部分是对状态的表示,以下部分是对状态的计算(即属性中要求的东西)
{
c[i][j]=c[i-1][j];
if(a[i]<=j) c[i][j]=max(c[i][j],c[i-1][j-a[i]]+b[i] );
}
}
AcWing 1015. 摘花生
for(int i=1;i<=m;i++)
{
for(int j=1;j<=n;j++)
///以上部分是状态表示,以下部分是状态计算
b[i][j]=max(b[i-1][j]+a[i][j],b[i][j-1]+a[i][j]);
}
AcWing 895. 最长上升子序列
for(int i=1;i<=n;i++)
{
f[i]=1;
for(int j=1;j<=i;j++)
{
///以上为状态表示,以下为状态计算
if(a[j]<a[i]) f[i]=max(f[i],f[j]+1);
}
}
AcWing 1212. 地宫取宝
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(i==1&&j==1) continue ;
for(int u=0;u<=k;u++)
{
for(int v=0;v<=13;v++)
///以上是对状态的表示,以下是对状态的计算
{
int &val=f[i][j][u][v];
val=(val+f[i-1][j][u][v])%MOD;
val=(val+f[i][j-1][u][v])%MOD;
//以上是对不取的两种情况的讨论
//以来是对取的两种情况的讨论
if(u>0 && v==a[i][j])
{
for(int c=0;c<a[i][j];c++)
{
val=(val+f[i-1][j][u-1][c])%MOD;
val=(val+f[i][j-1][u-1][c])%MOD;
}
}
}
}
}
}
可以发现,基本流程是 输入——for循环表示状态——写条件——输出
在进行状态计算时,我们一般是按由后往前来寻找突破口。
即 最后一个元素优先级(背包问题)>最后两个元素间关系优先级(花生问题)>倒数第二个元素(最后一个元素看不出区分,都是同一个状态时,倒数第二个元素可以把集合进行分类)
当然,有时为了达到不少,不重复的原则,还有两种方面的结合,如地宫寻宝问题(不但讨论最后一个取不取,当取的时候,倒数第二个到底价值为多少也要讨论)。