dp最长公共子串LCS
http://acm.hdu.edu.cn/showproblem.php?pid=1159
这题可用递归解出
(1)递归方法求最长公共子序列的长度
1)设有字符串a[0...n],b[0...m],下面就是递推公式。
当数组a和b对应位置字符相同时,则直接求解下一个位置;当不同时取两种情况中的较大数值。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<stdio.h>//会超时 #include<string.h> char a[100000],b[100000]; int lena,lenb; int LCS(int i,int j) { if(i>=lena || j>=lenb) return 0; if(a[i]==b[j]) return 1+LCS(i+1,j+1); else return LCS(i+1,j)>LCS(i,j+1)? LCS(i+1,j):LCS(i,j+1); } int main() { while(scanf("%s %s",a,b)!=EOF) { lena=strlen(a); lenb=strlen(b); printf("%d\n",LCS(0,0)); } return 0; }
但是这样子的方法会超时
接下来就是动态规划
(2)动态规划求最长公共子序列的长度
动态规划采用二维数组来标识中间计算结果,避免重复的计算来提高效率。
1)最长公共子序列的长度的动态规划方程
设有字符串a[0...n],b[0...m],下面就是递推公式。字符串a对应的是二维数组num的行,字符串b对应的是二维数组num的列。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<stdio.h> #include<string.h> int ans[1000][1000]; int max(int a,int b) { return a>b?a:b; } int main() { int i,j,lena,lenb; char a[10000],b[10000]; while(scanf("%s %s",a,b)!=EOF) { lena=strlen(a); lenb=strlen(b); for(i=0;i<=lena;i++) for(j=0;j<=lenb;j++) ans[i][j]=0;//初始化为0 for(i=1;i<=lena;i++) for(j=1;j<=lenb;j++) { if(a[i-1]==b[j-1])//如果都相等,两个指针都前移并将该处的子串长度加一 ans[i][j]=1+ans[i-1][j-1]; else ans[i][j]=max(ans[i][j-1],ans[i-1][j]);//否则保留两个子串前个阶段最大的那个 } printf("%d\n",ans[lena][lenb]); } return 0; }
还写出了一个错误的代码。。。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<stdio.h> #include<string.h> int ans[1000][1000]; int max(int a,int b) { return a>b?a:b; } int main() { int i,j,lena,lenb; char a[10000],b[10000]; while(scanf("%s %s",a,b)!=EOF) { lena=strlen(a); lenb=strlen(b); for(i=0;i<lena;i++) for(j=0;j<lenb;j++) ans[i][j]=0;// for(i=0;i<lena;i++) for(j=0;j<lenb;j++)// { if(a[i]==b[j]) ans[i+1][j+1]=1+ans[i][j];// else ans[i+1][j+1]=max(ans[i][j+1],ans[i+1][j]);//这里错误,此时二者还都是未知 } printf("%d\n",ans[i][j]); } return 0; }