前言
学完动态规划,做题,比赛还是容易卡
想了想原因
1.刷题量还不够
2.还是没吃透里面的思想
所以,准备写点博客,再复习一下动态规划。
数字三角形模型
就是分析二维平面上,通过怎么转移状态,来获取到想要的情况
比如二维平面上,每个点都有大小
求从起点到终点的所有路径中每个点之和的最大值;
这就要分析,每一次怎么转移状态,才能保证是最大的
在动态规划里,考虑状态转移基本上都是分析最后一次的操作怎么进行
比如我们不能走多余的路,所以从起点到终点只能向右,向下走。
对于红点,能转移到红点的状态有两个,第一个是从上方转移过来,第二个是从左边转移过来,我们对于所有能转移到红点的状态取最大值,就可以保证一直转移的是最大值。(同理最小值也是),最后看转移到终点时,所获得的最大状态是上面。
该模型一般有两类
1.单路径
典型的就是数字三角形本身
传送门
题目大意
写一个程序来查找从最高点到底部任意处结束的路径,使路径经过数字的和最大。每一步可以走到左下方的点也可以到达右下方的点。
做法
就单纯的分析一条路径就行,找转移到该点时,最大的路径和
状态表示
f [ i , j ] 表示转移到该点时的最大路径和
状态计算
f[i,j] 可以由 f[i-1,j-1] (左上) 和 f[i-1,j] (右上) 转移过来。
f[i,j] =max(f[i-1,j-1],f[i-1,j])
核心代码
for(int i=0;i<=n;i++)
for(int j=0;j<=n;j++) f[i][j]=-0x3f3f3f3f; // 初始化所有为负无穷,表示不可取
// 因为该二维平面不是规则的,超过这个三角形的,不可取。
f[1][1]=a[1][1]; // 初始起点
for(int i=2;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
f[i][j]=max(f[i-1][j-1]+a[i][j],f[i-1][j]+a[i][j]); // 用来自左上和右上路径的最大值来转移
}
}
经典题目还有 采花生
2.双路径
该模型一般问在 二维平面里怎么走两次,使的路径上的点和最大(不能重复或者让走过路径上的点为0)
这种只能同时走,不能分两次走
分开两次走(贪心):第一次走到(n, n)求出最大值并记录路径令路径上点收益为0后再走一次。
第一次走为局部最优并且也对第二次走造成了影响,第二次走是在第一次影响下所能走的局部最优,不具备“无后效性”,因此分开两次走并不是全局最优解
典型题目 方格取数
题目大意
从A到B只能向下和向右,求走两次的最大值
做法
一般是一次性走两条路径,注意特判重合的情况,在曼哈顿距离中,当路径长度一样时,当横坐标(纵坐标)一样时,两个路径在该点重合。
状态表示
f
[
l
e
n
]
[
i
1
]
[
i
2
]
f[len][i_1][i_2]
f[len][i1][i2] 表示路径一共len长,第一个路径的纵坐标为
i
1
i_1
i1,第二个路径的纵坐标为
i
2
i_2
i2
状态计算
对于一条路径来说 该点可以由上方的路径或者左方的路径转移过来,有两种状态
那两个路径一共有四个状态
路径 1 路径2
从上方 从上方
从上方 从左方
从左方 从左方
从左方 从上方
核心代码
for(int len=2;len<=2*n;len++)
{
for(int i1=1;i1<=n;i1++)
{
for(int i2=1;i2<=n;i2++)
{
int j1=len-i1,j2=len-i2;
if(j1<=n && j1>=1 && j2<=n && j2>=1) // 保证合法,不出界
{
int v=a[i1][j1]; // 路径1点的大小
if(i1!=i2 )
{
v+=a[i2][j2]; // 如果两个路径点不重合,再加上路径2的点
}
int &s=f[len][i1][i2];
// int dx[]={0,0,-1,-1},dy[]={0,-1,-1,0};
for(int k=0;k<4;k++)
{
s=max(s,f[len-1][i1+dx[k]][i2+dy[k]]); // 求四个状态的最大值
}
s+=v;
}
}
}
}
下一篇
动态规划回顾(二)线性dp