先练习一些简单的dp,慢慢来,主要是要找到状态转移方程是怎么写的,我也有时候想不到,哎这点就是动态规划最难的地方,慢慢来。
当解决动态规划问题时,状态转移方程是非常重要的一部分,它描述了当前状态与之前状态之间的关系。
在最长公共子序列问题中,我们可以通过以下步骤来推导状态转移方程:
定义状态:我们定义dp[i][j]表示长度为i的A序列和长度为j的B序列的最长公共子序列的长度。
考虑最后一步:在求解最长公共子序列的问题中,我们可以考虑最长公共子序列的最后一个元素,即A[i]和B[j]。
这样,我们可以将问题分解为两个子问题:
如果A[i]等于B[j],那么最长公共子序列的最后一个元素就是A[i](或者B[j]),并且最长公共子序列的长度应该是dp[i-1][j-1] + 1。
如果A[i]不等于B[j],那么最长公共子序列的最后一个元素肯定不是A[i](或者B[j]),
所以我们需要在A[1:i-1]和B[1:j]或者A[1:i]和B[1:j-1]中寻找最长公共子序列。
写出状态转移方程:根据上述分析,我们可以得到状态转移方程:
如果A[i]等于B[j],则dp[i][j] = dp[i-1][j-1] + 1
如果A[i]不等于B[j],则dp[i][j] = max(dp[i-1][j], dp[i][j-1])
通过这样的推导过程,我们可以写出最长公共子序列问题的状态转移方程。
这个方程描述了当前状态与之前状态之间的关系,帮助我们在动态规划中有效地求解问题。
#include<iostream>
using namespace std;
//
// 1.设计状态(难):dp[i][j] 表示长度为i的A序列和长度为j的B序列的最长公共子序列的长度
// 2.状态转移方程(较难):
// {
// 1.Ai=Bj 则 dp[i][j]=dp[i-1][j-1]+1
// 2.Ai!=Bj 则 dp[i][j]=msx(dp[i-1][j],dp[i][j-1])
// }
using ll =long long;
int n, m;
ll A[1005], B[1005];
int dp[1005][1005];
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; i++)cin >> A[i];
for (int i = 1; i <= m; i++)cin >> B[i];
for(int i=1;i<=n;i++)
for (int j = 1; j <= m; j++)
{
if (A[i] == B[j])dp[i][j] = max(dp[i][j], dp[i - 1][j - 1] + 1);
else dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);//如果他们不相等的话//说明他们的最后一位肯定不是a[i]或者b[i]
//所有我们只需要找到1到i-1的范围和1到j-1的访问去寻找最长的子序列//他们会根据前面的状态转移影响后面的状态转移
}
cout << dp[n][m];
// if(a[i]>a[j]){
// c[i]=max(c[i],c[j]+a[i]);
return 0;
}
本人也是小白,对应动态规划也不会,按照我现在的理解,我想跟我前面发的那个最大花之能量的博客有点相似的,只不过那个是以最后的元素结尾。
我们用一个数组来存放我们变化的值(也就是查找的共有的子序列的长度)
在相等的时候,我们看是把它放入dp中取大的那个,然后不想等的情况,我们看最长公共子序列看是dp[i-1][j]和dp[i][j-1]看谁的大,我们就更新
也就是选A还是B的最长公共子序列,本人理解就这么多,听大佬说动态规划没有几百题是没有感觉的,我还需要多练.。然后如果我有错误的地方,请大家给我说出来,一起学习一起进步嘛。