他们都是用dp做;复杂度都是O(N方)

有一个大佬的博客写的很详细,是关于最长公共子序列的:https://blog.csdn.net/hrn1216/article/details/51534607#comments;

我觉得一开始处理这种问题比较棘手,无从下手,而dp一般有两种状态转移的思考方式,一种是正着,一种是倒着,而且dp一般记录的信息都是按照一定顺序,以什么结尾的答案,或者以什么开头的答案具有的一种性质,然后我们按顺序增加或减少开头或者结尾,形成一种状态的传递关系,还有一些状态的传递可能是像dfs中有某一状态走到一部走到另一状态,还是按顺序,由小规模到大规模;假设两个字符串长度为len1,和len2,那么我们要知道他们的公共子序列,就要知道小一些规模的同一个问题,这里我们通过缩短长度来缩小规模;

这里可以分两种情况,s1[len1]=s2[len2],那么它的答案dp[len1][len2]=dp[len1-1][len2-1]+1;

如果s1[len1]!=s2[len2], s1[len1],s2[jlen2],最多有一个是有效信息存在答案里面和另一个窜前面的元素配对,所以 dp[len1][len2]=max(dp[len1-1][len2],dp[len1][len2-1]);这样就缩小了规模,我们按照这种方法推广出去;

 

我们dp[i][j]代表s1 窜前i个字母和s2窜 前 j 个字母最长公共子序列,如果s1[i]=s2[j] ,dp[i][j]=d[i-1][j-1]+1,如果s1[i]!=s2[j], s1[i],s2[j],最多有一个是有效信息就是可能存在答案里面,和前面的配对,所以 dp[i][j]=max(dp[i-1][j],dp[i][j-1]);

大致代码如下:(记得初始化)

 1 #include<iostream>
 2 using namespace std;
 3 char a1[1001],a2[1001],dp[1001][1001]={0};
 4 int main()
 5 {
 6     int n1,n2;
 7     cin>>n1>>n2;
 8     for(int i=1;i<=n1;i++)
 9         cin>>a1[i];
10     for(int j=1;j<=n2;j++)
11         cin>>a2[j];
12     for(int i=1;i<=n1;i++)
13         for(int j=1;j<=n2;j++)
14             if(a1[i]==a2[j])
15                 dp[i][j]=dp[i-1][j-1]+1;
16             else
17                 dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
18     cout<<dp[n1][n2]; 
19 }

 

posted on 2020-04-18 17:13  很绝望  阅读(148)  评论(0编辑  收藏  举报