显然,在遇到两个字符串需按位进行操作的问题时,我们首先会想到将两个字符串按位遍历;
类如:
int dp[][]; //
for(int i=1;i<=a.size();i++)
{
for(int j=1;j<=b.size();j++)
{
if(a[i]==b[i]) {}
else{}
}
}
dp[i][j]的i和j分别代表每个字符串遍历到了第几个字母;
那么,作为一个dp初学者,我们不妨照葫芦画瓢,对本题的s、t字符串进行按位遍历(以下我设a、b)字符串。
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
string a,b;
int dp[5005][5005];
int ans=0;
signed main()
{
cin>>a>>b;
int len1=a.size();
int len2=b.size();
以上为我的代码准备;
这个时候,我们进行可以很简单地想出来的第一步!
for(int i=1;i<=len1;i++)
{
for(int j=1;j<=len2;j++)
{
if(a[i-1]==b[j-1])
{
dp[i][j]=dp[i-1][j-1]+1;
}
显然,我们可以知道,如果a[i]==b[j],那么ans是会++的;
而我们又知道!dp的特质是新的子问题的解,是由旧的子问题的解得来的!
那么我们很容易就可以得到,dp[i][j]=dp[i-1][j-1];
好的,问题来了,我们知道新解是由旧解得来的,我们又如何确定“旧解”是什么呢?
因为数据范围可以允许进行n^2的复杂度,并且需要遍历两个字符串;
并且!我们易知dp[i][j]一般是由dp[i-1][j]/dp[i][j-1]/dp[i-1][j-1]得到的;
所以!易得结果!
//第二步
else if(a[i-1]!=b[j-1])
{
dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
}
我个人认为比较有难度的是这个。
首先,我们秉持着这个——>dp的本质是继承/选择;
那么当a[i]!=b[j]时,继承什么?又选择什么呢?
继承:
显然我们要从dp[i-1][j]和dp[i][j-1]中继承;
再补一点原因:
(1)因为a[i]!=b[j],所以本质上这一步是没有即时性的操作的;所以一定是要从前面的旧解走的;
(2)显然dp[i-1][j-1]已经用过了,我们可以往dp[i-1][j]和dp[i][j-1]处想;
选择:
(1)显然是选择最大的;
(2)二维和“两个字符串的对称性”;
好的;现在我们就写出了该dp的状态转移方程。
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
string a,b;
int dp[5005][5005];
signed main()
{
while(cin>>a>>b)
{
int len1=a.size();
int len2=b.size();
dp[0][0]=0;
if(a[0]==b[0])
{
dp[1][1]=1;
}
for(int i=1;i<=len1;i++)
{
for(int j=1;j<=len2;j++)
{
if(a[i-1]==b[j-1])
{
dp[i][j]=dp[i-1][j-1]+1;
}
else if(a[i-1]!=b[j-1])
{
dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
}
}
}
cout<<dp[len1][len2]<<endl;
}
return 0;
}

京公网安备 11010502036488号