动态规划
直接上动态规划方程:
- 如果用填表来说,填表的过程是首先把第0行第0列赋值为0 。
- 然后一行一行从左到右填表。
#include<iostream>
using namespace std;
const int NUM = 51;
int dp[NUM][NUM];
int b[NUM][NUM]; // 记录位置
void LCSLength(int m, int n, char x[], char y[])
{
for (int i = 1; i <= m; ++i)
{
dp[i][0] = 0;
}
for (int i = 1; i <= n; ++i)
{
dp[0][i] = 0;
}
for (int i = 1; i <= m; ++i)
{
for (int j = 1; j <= n; ++j)
{
if (x[i] == y[j])
{
dp[i][j] = dp[i - 1][j - 1] + 1;
b[i][j] = 1;
}
else if (dp[i - 1][j] > dp[i][j - 1])
{
dp[i][j] = dp[i - 1][j];
b[i][j] = 2;
}
else
{
dp[i][j] = dp[i][j - 1];
b[i][j] = 3;
}
}
}
}
void LCS(int i, int j, char x[])
{
if (i == 0 || j == 0)
return;
if (b[i][j] == 1)
{
LCS(i - 1, j - 1, x);
cout << x[i] << " ";
}
else if (b[i][j] == 2)
LCS(i - 1, j, x);
else
LCS(i, j - 1, x);
}
int main()
{
int m, n;
char x[NUM], y[NUM];
cin >> m >> n;
for (int i = 1; i <= m; ++i)
{
cin >> x[i];
}
for (int i = 1; i <= n; ++i)
{
cin >> y[i];
}
LCSLength(m, n, x, y);
for (int i = 1; i <= m; ++i)
{
for (int j = 1; j <= n; ++j)
{
cout << dp[i][j] << " ";
}
cout << endl;
}
cout << "--------------------" << endl;
for (int i = 1; i <= m; ++i)
{
for (int j = 1; j <= n; ++j)
{
cout << b[i][j] << " ";
}
cout << endl;
}
cout << "--------------------" << endl;
LCS(m, n, x);
return 0;
}
/*
4 7
B C D B
A B C B D A B
*/
递归
这里自己类比了矩阵乘积的动态规划转递归的思路,把这道题用递归的方法做了一遍,感觉比动态规划麻烦一些,因为老师没有给代码,所以这道题是按照自己的思路解的,过程中有很多麻烦的地方,优化也有很多不足,但是总算是自己折腾出来了。
- 递归求解方程类似于动态规划方程。
- 始终保证x[]是短字符数组,y[]是长字符数组,因为在做题的过程中出现了重复值。所以我用的解决思路是定义了一个b数组,并且b数组始终保存的是段字符数组是否已经有重合对象,如果已经有了重合对象,那之后就不继续找了。
- 最后用了栈来存储相同的字符,最后逆序输出。
#include<iostream>
#include<algorithm>
#include<stack>
using namespace std;
const int NUM = 51;
int k;
int b[NUM];
stack<char>s;
int LCSLenth(int i, int j, char x[], char y[])
{
if (i == 0 || j == 0)
return 0;
if (x[i] == y[j] && b[i] == 1)
{
b[i] = 0;
s.push(x[i]);
return LCSLenth(i - 1, j - 1, x, y) + 1;
}
return max(LCSLenth(i - 1, j, x, y), LCSLenth(i, j - 1, x, y));
}
int main()
{
int m, n;
char x[NUM], y[NUM], t[NUM];
cin >> m >> n;
k = min(m, n);
for (int i = 1; i <= k; ++i)
{
b[i] = 1;
}
if (m > n) // 始终保证x[]是短字符数组,y[]是长字符数组
{
for (int i = 1; i <= m; ++i)
{
cin >> y[i];
}
for (int i = 1; i <= n; ++i)
{
cin >> x[i];
}
swap(m, n);
}
else
{
for (int i = 1; i <= m; ++i)
{
cin >> x[i];
}
for (int i = 1; i <= n; ++i)
{
cin >> y[i];
}
}
LCSLenth(m, n, x, y);
while (!s.empty())
{
cout << s.top() << " ";
s.pop();
}
return 0;
}
/*
4 7
B C D B
A B C B D A B
7 4
A B C B D A B
B C D B
*/
备忘录优化
类似于矩阵相乘的思想,用数组存储了一下,用空间换大量的时间。
int LCSLenth(int i, int j, char x[], char y[])
{
if (i == 0 || j == 0)
return 0;
if (dp[i][j] > 0)
return dp[i][j];
if (x[i] == y[j] && b[i] == 1)
{
b[i] = 0;
s.push(x[i]);
dp[i][j] = LCSLenth(i - 1, j - 1, x, y) + 1;
return LCSLenth(i - 1, j - 1, x, y) + 1;
}
dp[i][j] = max(LCSLenth(i - 1, j, x, y), LCSLenth(i, j - 1, x, y));
return max(LCSLenth(i - 1, j, x, y), LCSLenth(i, j - 1, x, y));
}