今天研究了一下动态规划,思想很简单:循序渐进,局部推到整体。但运用起来还是不太好想的。
下面用动态规划解LCS最大公共子串问题
写了两个函数LCS和LCS_Inhance,前者用矩阵实现(用于理解原理),后者用两个数组实现(节省空间)。
由于初学,不做过多评论,已免误导读者。
代码如下:
#include<iostream>
#include<string>
using namespace std;
int max(int x, int y, int z){
if (x > y)
return x > z ? x : z;
else
return y > z ? y : z;
}
int LCS(const string& s1,const string& s2){//用矩阵,暂用空间大
if (s1.empty() || s2.empty())
return 0;
int len_min = s1.size() <= s2.size() ? s1.size() : s2.size();
int **map = new int*[s1.size()];
for (int i = 0; i < s1.size(); ++i)
map[i] = new int[s2.size()];
for (int i = 0; i < s1.size(); ++i){
if (s1[i] == s2.front()){
for (; i < s1.size(); ++i)
map[i][0] = 1;
break;
}
map[i][0] = 0;
}
for (int i = 0; i < s2.size(); ++i){
if (s1.front() == s2[i]){
for (; i < s2.size(); ++i)
map[0][i] = 1;
break;
}
map[0][i] = 0;
}
for (int i = 1; i < len_min; ++i){
for (int j = i; j < s1.size(); ++j){
if (s1[j] == s2[i])
map[j][i] = max(map[j][i - 1], map[j - 1][i], map[j - 1][i - 1] + 1);
else
map[j][i] = max(map[j][i - 1], map[j - 1][i], map[j - 1][i - 1] );
}
for (int j = i; j < s2.size(); ++j){
if (s1[i] == s2[j])
map[i][j] = max(map[i - 1][j], map[i][j - 1], map[i - 1][j - 1] + 1);
else
map[i][j] = max(map[i - 1][j], map[i][j - 1], map[i - 1][j - 1] );
}
}
int tep= map[s1.size() - 1][s2.size() - 1];
for (int i = 0; i < s1.size(); ++i)
delete[] map[i];
return tep;
}
int LCS_Inhance( char* s1, char* s2){//用两个数组,暂用空间小,关键是需要用一个temp存储斜对角的元素,以免写时覆盖
if (strlen(s1) == 0 || strlen(s2) == 0)
return 0;
if (strlen(s1)>strlen(s2)){
s1 = (char*)((int)s1 ^ (int)s2);
s2 = (char*)((int)s1 ^ (int)s2);
s1 = (char*)((int)s1 ^ (int)s2);
}
int h = strlen(s1);
int l = strlen(s2);
int *pl = new int[l];
int *ph = new int[h];
for (int i = 0; i < l; ++i){
if (s1[0] == s2[i]){
for (; i < l; ++i)
pl[i] = 1;
break;
}
pl[i] = 0;
}
for (int i = 0; i < h; ++i){
if (s2[0] == s1[i]){
for (; i < h; ++i)
ph[i] = 1;
break;
}
ph[i] = 0;
}
for (int i = 1; i < h; ++i){
int temp1,temp2;
temp1 = pl[i];
temp2 = ph[i];
if (s1[i] == s2[i]){
pl[i] = max(ph[i], pl[i], pl[i - 1] + 1);
ph[i] = max(pl[i], ph[i], ph[i - 1] + 1);
}
else{
pl[i] = max(ph[i], pl[i], pl[i - 1] );
ph[i] = max(pl[i], ph[i], ph[i - 1] );
}
for (int j = i+1; j < l; ++j){
if (s2[j] == s1[i]){
int temp = max(temp1 + 1, pl[j], pl[j - 1]);
temp1 = pl[j];
pl[j] = temp;
}
else{
int temp = max(temp1, pl[j], pl[j - 1]);
temp1 = pl[j];
pl[j] = temp;
}
}
for (int j = i + 1; j < h; ++j){
if (s2[j] == s1[i]){
int temp = max(temp2 + 1, ph[j], ph[j - 1]);
temp2 = ph[j];
ph[j] = temp;
}
else{
int temp = max(temp2, ph[j], ph[j - 1]);
temp2 = ph[j];
ph[j] = temp;
}
}
}
//cout << pl[l - 1] << '\t' << ph[h - 1] << endl;
int result = pl[l - 1];
delete[] pl, ph;
return result;
}
int main(){
FILE* pf;
freopen_s(&pf, "c:\\acm_input.txt", "r",stdin);
string s1, s2;
int input_num = 4;
for (int i = 0; i < input_num; ++i){
cin >> s1 >> s2;
cout << LCS(s1, s2) << endl;
char *ps1 = new char[s1.size() + 1];
char *ps2 = new char[s2.size() + 1];
ps1[s1.size()] = '\0';
ps2[s2.size()] = '\0';
strncpy(ps1, s1.c_str(), s1.size());
strncpy(ps2, s2.c_str(), s2.size());
cout<<LCS_Inhance(ps1, ps2)<<endl;
delete[] ps1, ps2;
}
return 0;
}