算法第三章上机实践报告
1.1 问题描述
2个字符串A,B。用最少操作将A转换为B。
操作包括 (1)删除一个字符; (2)插入一个字符; (3)将一个字符改为另一个字符。
输入格式:
第一行输入字符串A,第二行输入字符串B。
输出格式:
输出最少操作数。
输入样例:
fxpimu
xwrs
输出样例:
5
1.2 算法描述
使用动态规划的方法填表实现。
1.3 问题求解
①创建动态二维数组dp
int dp[2005][2005]; //比A,B长度略大,防止数组越界
②当一个字符串为空时,则最少操作数为另一字符串的长度
int n = strlen(A + 1), m = strlen(B + 1); // A和B从1下标读入,计算长度也需要从1下标计数
for (int i = 0; i <= m; i++) dp[0][i] = i;
for (int i = 0; i <= n; i++) dp[i][0] = i;
③建立双重循环,不断填入dp[i][j],
1.若字符串A[i] == B[j], 则 dp[i][j] = dp[i - 1][j - 1] ,即不需要进行编辑;
2.若字符串A[i] != B[j],则在 (dp[i][j - 1] + 1, dp[i - 1][j] + 1, dp[i - 1][j - 1] + 1)进行比较,取最小值即为dp[i][j]的值。
分别对应操作:
(1)将A串的最后字符删除;
(2)将A串的最后插入B串的最后的字符;
(3)将B串的最后一个字符替换为A串的最后一个字符;
④题目所求的字符串A转换成字符串B的最少操作数为 dp[n][m];
代码如下:
#include<bits/stdc++.h> using namespace std; const int N = 2005; char a[N], b[N]; int f[N][N]; int main() { scanf("%s%s", a + 1, b + 1); int n = strlen(a+1), m = strlen(b+1); for(int i = 0; i <= m; i++) f[0][i] = i; for(int i = 0; i <= n; i++) f[i][0] = i; 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]; else f[i][j]=min( min(f[i-1][j] + 1,f[i][j-1] + 1), f[i-1][j-1] + 1); printf("%d\n", f[n][m]); return 0; }
时间复杂度:
O(N^2)
填表顺序:
心得体会
动态规划与分治法类似,都是把大问题拆分成小问题,通过寻找大问题与小问题的递推关系,解决一个个小问题,最终达到解决原问题的效果。但不同的是,分治法在子问题和子子问题等上被重复计算了很多次,而动态规划则具有记忆性,通过填写表把所有已经解决的子问题答案纪录下来,在新问题里需要用到的子问题可以直接提取,避免了重复计算,从而节约了时间,所以在问题满足最优性原理之后,用动态规划解决问题的核心就在于填表,表填写完毕,最优解也就找到。
动态规划比较抽象,并且一般不拘泥固定形式结构。这就需要我们多做题,拓展思维,针对不同问题列出不同递归方程式,灵活应对不同问题。