前言
上次我们仅仅只是对动态规划的一些情景进行讨论比较基础,这次将进行题型讲解,在题型中对动态规划有更深层次的理解,毕竟想学好算法可不仅仅只是理解概念就可以的,还要多加练习才行。下面是几类动态规划比较基础的题型,我将根据类别将逐一进行讲解。
注:本文由于篇幅原因均未给出完整代码,完整代码由大家理清思路自主实现,只给出主要算法部分
- 最长上升子序列
题目分析:首先我们看到此题求解目标是最长上升子序列,所以我们随便给出一个序列来作为例子进行较为直观的讲解:
1 5 4 3 8 9 0 2 3 4 5 7 8 6 9
我们可以看到序列集合整体呈无序排列,我们需找出目标集合最长的上升子集,我们先找其状态转移方程,但是这里会牵扯到一个问题,我们在找状态转移方程时,会自然而然想到前i个最长上升子序列=前i-1个上升子序列+1(如果第i个大于第i-1个时),所以将得到以下代码
if(a[i]>a[i-1])
F[i]=F[i-1]+1;
else
F[i]=F[i-1];
第i个状态将由第i-1个状态推导而来,但是在这里我们不难发现,第i个状态的上一个状态并不唯一,例如1 5 4 3 8 9 0 2如果按照此种方法进行推导将得到最长上升子序列为5,而实际则为4,为避免这种情况我们应该用下面方法进行规避:
for(int i=0;i<n;i++)
{
cin>>a[i];
F[i]=1;
}
for(int i=1;i<n;i++)
for(int j=0;j<i;j++)
if(a[i]>a[j])
F[i]=max(F[i],F[j]+1);
- 最长公共子序列
注:(1)对序列 1,3,5,4,2,6,8,7来说,序列3,4,8,7 是它的一个子序列。
(2)对序列 1,3,5,4,2,6,8,7和序列 1,4,8,6,7,5 来说序列1,8,7是它们的一个公共子序列。
有了上面的注释后我们来考虑这个问题首先将问题进行分解,(至于用自顶向下还是自底向上由你选择)我们还是先找转移方程,F[i][j]是A串前i个与B串前j个的最长公共子序列,接下来我们进行判断
if(A[i]!=B[j])
DP[i][j]=max(DP[i-1][j],DP[i][j-1]);
else
DP[i][j]=DP[i-1][j-1]+1;
我比较喜欢自底向上推导所以,用for循环进行枚举,有以下代码:
for(int i = 1; i <= A1; i++)
for(int j = 1; j <= B2; j++)
if(a[i - 1] == b[j - 1])
DP[i][j] = DP[i - 1][j - 1] + 1;
else
DP[i][j] = max(DP[i][j - 1], DP[i - 1][j]);
-
合唱队问题
先给出问题描述:
对问题进行分析我们不难看出实际上是一道求最大上升子序列和最大下降子序列的问题,所以这道题将不多赘言,大家可以进行自行实现。
-
最长滑雪道问题
题目大意:
给你一个矩阵,当做滑雪场,矩阵的每个单元中的数代表高度,滑雪者只能从高的滑到低的地方,且方向只能是上,下,左和右,问滑雪者最长能滑几个单元?*解析* :我们可以从矩阵上每个点进行深搜,然后对每个点进行动态规划dp[i][j]=max(dp[上下左右])+1,并且要进行判断位置是否可以行进,因为我们应选择向低的位置行进。