算法第三章上机实践报告

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)

填表顺序:

心得体会

动态规划与分治法类似,都是把大问题拆分成小问题,通过寻找大问题与小问题的递推关系,解决一个个小问题,最终达到解决原问题的效果。但不同的是,分治法在子问题和子子问题等上被重复计算了很多次,而动态规划则具有记忆性,通过填写表把所有已经解决的子问题答案纪录下来,在新问题里需要用到的子问题可以直接提取,避免了重复计算,从而节约了时间,所以在问题满足最优性原理之后,用动态规划解决问题的核心就在于填表,表填写完毕,最优解也就找到。

动态规划比较抽象,并且一般不拘泥固定形式结构。这就需要我们多做题,拓展思维,针对不同问题列出不同递归方程式,灵活应对不同问题。

posted @ 2021-10-26 22:27  haiou、  阅读(32)  评论(0编辑  收藏  举报