问题分析
我觉得这题的状态分成两半考虑比较方便,按两个序列末尾的字符是不是相等来区分。
如果两个字符相等,就可以直接转移到f[i-1][j-1]
,不相等的话,两个字符一定有一个可以抛弃,可以对f[i-1][j],f[i][j-1]
两种状态取max
来转移。
代码
#include <iostream>
using namespace std;
const int N = 1010;
int n, m;
char a[N], b[N];
int f[N][N];
int main() {
cin >> n >> m >> a + 1 >> b + 1;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (a[i] == b[j]) {
f[i][j] = f[i - 1][j - 1] + 1;
} else {
f[i][j] = max(f[i - 1][j], f[i][j - 1]);
}
}
}
cout << f[n][m] << '\n';
return 0;
}
f[i][j] 表示在第一个序列的前i个字母中出现并且在第二个序列的前j个字母中出现的最大值
以第i个和第j个字母是否相同来划分
如果相同 f[i][j] = f[i - 1][j - 1] + 1
如果不相同 f[i][j] = max(f[i - 1][j], f[i][j - 1])
因为如果不相同,那么此时f[i][j]的值肯定不会大于f[i - 1][j]和f[i][j - 1]的最大值
那么一定会等于f[i - 1][j]和f[i][j - 1]的最大值
佬儿们,这样会不会好理解一点hh
我不是佬,但我感觉没啥毛病hh
写的非常 #好
不明白为什么只有相同才可以{f[i][j] = f[i - 1][j - 1] + 1},如果a[i]和b[j]都是公共子序列里面的,但是位置不同难道不能转移吗?
我写的是
{dp[i][j]=max(dp[i-1][j],dp[i][j]);
dp[i][j]=max(dp[i][j],dp[i-1][j-1]+1);
}
但是 错了;
求大佬解答
比如a序列:abcde,b序列:bcdf,因为此时e与f不等,即a[5]!=b[4]
所以此时dp[5][4]=dp[4][3],如果此时再dp[i][j] = dp[i - 1][j - 1] + 1就多加了
秒
而你 就是我的英雄 小turtle!
a[i]和b[j]都是值,而不是位置,因为它们值不同所以不可能同时作为公共子序列的结尾
没毛病
哇!太棒了!没有题解我怎么学啊˃̣̣̥᷄⌓˂̣̣̥᷅
你对f[i][j]的理解错了,f[i][j]代表的是s1前i位和s2前j位的最长公共子序列,所以如果a[i]和b[j]都是f[i][j]的最长公共子序列里的,必定是f[i][j]的最长公共子序列的末尾元素。甚至有一个是最长公共子序列里的,必定也是f[i][j]的末尾元素, 不会出现位置不同的情况。
哎哟,这想法可以!
优雅
分成4块死活没看懂智商不够捏
跟我想的一样,我也在思考那个if(a[i]==b[j])里,max有点多余
牛哇,不愧是利维亚的杰洛特👍
大佬们可以解答一下我这样为啥不能AC吗
#include[HTML_REMOVED]
#include[HTML_REMOVED]
using namespace std;
const int N = 1010;
int n, m;
char a[N], b[N];
int f[N][N];
int main()
{
scanf(“%d%d”, &n, &m);
//为啥这么写不对
for(int i = 1; i <= n; i ) scanf(“%c”, &a[i]);
getchar();
for(int i = 1; i <= m; i ) scanf(“%c”, &b[i]);
}
兄弟,你解决了吗,我也好奇为什么scanf不可以,但cin可以
scanf(“%d%d”, &n, &m);这下面还要getchar();
回车算一个字符
nb
很优雅的判断做法
为什么下标要从1开始,我从0开始不对
0-1=-1不行,数组不能负下标
%%%
nb
orz
orz
666
可能都会抛弃,不是一定的
醍醐灌顶
如果范围很大该咋办
## 这样啊
wc,nb,问题解释的如此通俗易懂,tql
tql