/**
动规是必考题目,有时甚至考好几道,非常灵活,非常巧妙
最长公共子序列是动规的经典题目,也被用于好多教材的例子
谈到动态规划,我对其也是最肤浅的认识,感觉和记忆化搜索
是不分家的,我一般都是先把整个问题局部化,然后分析局部
大致写个 转移方程 再验证是否正确并考虑特殊情况,不管怎
么样,只要经过大量重复练习,神马都是浮云
求其最长的子序列,如:
abcdef
bdaf
这两个串的最长子序列为 bdf
子序列和子串不一样,子串必须连续,子序列不需要连续,它
只抢到字母的先后顺序,如果求最长子串,这就难了,当然可
以被后缀数组秒杀,后面会贴
只要提到两个串,然后又和DP 挂钩,大多都是二维数组f[M][M],
M为串的最大长度,f[i][j] 表示a串前 i的字符和b 串前 j 的字
符所得到的最优解,逐个递推到f[M][N];
这个并不好理解,只有自己一遍遍手动模拟,然后才会有感觉,
char s1[M], s2[M];
scanf("%s%s", s1+1, s2+1);
//这样输入可以使下面处理简单点,即s1[1] 为串的第一个字符,而不是s1[0]
int f[M][M]; //用来保存子问题和问题的结果
//f 数组初始化为0
//设l1, l2 为s1, s2串长度
for (int i=1; i<=l1; i++)
for (int j=1; j<=l2; j++) { //之所以从1 开始,因为下面有 f[i-1][j-1]
if (s1[i] == s2[j])
f[i][j] = f[i-1][j-1] + 1; //这是显然的
else
f[i][j] = max(f[i-1][j], f[i][j-1]); //如果不相等就继承一个最大的
}
上面虽然看起来简单,但是对于刚接触的编程的大学生理解起来也是很费劲的
如果用手也模拟不出来,最好还是本算法书看下具体意思了,相信几乎每本上面
都有这个例子
上面f[l1][l2] 给出了最常的公共子序列长度,可是如果想具体打印出来怎么办
当然得标记下
int path[M][M]; //这是一个标记数组,总共有3 种情况,所以有3 种取值
//初始化为0
for (int i=1; i<=l1; i++)
for (int j=1; j<=l2; j++) {
if (s1[i] == s2[j]) {
path[i][j] = 1; //这种情况标记为1
f[i][j] = f[i-1][j-1] + 1;
}
else if (f[i-1][j] > f[i][j-1]) {
path[i][j] = 2;
f[i][j] = f[i-1][j];
}
else {
path[i][j] = 3;
f[i][j] = f[i][j-1];
}
}
//现在path 已经标记了所有的步骤,现在来递归输出
void print(int i, int j) {
if (path[i][j] == 0)
return;
if (path[i][j] == 1) {
print(i-1, j-1);
printf("%c ", s1[i]); //当然也可以是 s2[j]
}
else if (path[i][j] == 2)
print(i-1, j);
else
print(i, j-1);
}
调用 print(l1, l2); 即可输出
POJ 2250
睡觉了,睡觉了,晚安
*/
收藏于 2012-01-15
来自于百度空间
DP 最长公共子序列并标记输出
最新推荐文章于 2020-12-03 23:20:12 发布
![](https://img-home.csdnimg.cn/images/20240711042549.png)