2016级算法第四次上机-F.AlvinZH的最“长”公共子序列

940 AlvinZH的最“长”公共子序列

思路

DP,难题。

\(dp[i][j]\) :记录A的前i个字符与B的前j个字符变成相同需要的最小操作数。

初始化:dp[i][0] = i, dp[0][i] = i。分别代表i次删除or添加操作。

三种操作得到dp[i][j],取其中最小值:

  • 替换:可能不需要替换,所以是dp[i-1][j-1]+Same(A[i-1],B[j-1]);
  • 删除:dp[i-1][j]+1;
  • 添加:dp[i][j-1]+1。

千万不要纠结操作的序列是A还是B!

其实这是《算法导论》上一个“编辑距离”问题,比较经典,有兴趣的同学可以看看书or百度看看。

分析

没法分析,DP岂是我等凡人能理解的,sad。

稍微分析,时间复杂度O(n^2)。

参考代码一

//
// Created by AlvinZH on 2017/10/16.
// Copyright (c) AlvinZH. All rights reserved.
//

#include <cstdio>
#include <cstring>

char A[1005], B[1005];
int dp[1005][1005];//记录A的前i个字符转换到B的前j个字符的最小操作数

inline int Same(char a, char b) {
    if(a == b) return 0;
    else return 1;
}
inline int MIN(int a, int b, int c) {
    if(a > b) a = b;
    if(a > c) a = c;
    return a;
}

int main()
{
    while(~scanf("%s %s", A, B))
    {
        int lenA = strlen(A);
        int lenB = strlen(B);

        for (int i = 0; i <= lenA; ++i)
            dp[i][0] = i;//i次删除操作
        for (int i = 0; i <= lenB; ++i)
            dp[0][i] = i;//i次添加操作

        for (int i = 1; i <= lenA; ++i) {
            for (int j = 1; j <= lenB; ++j) {
                dp[i][j] = MIN(dp[i-1][j-1]+Same(A[i-1],B[j-1]), dp[i-1][j]+1, dp[i][j-1]+1);
                //MIN(替换, 删除, 添加)
            }
        }

        printf("%d\n", dp[lenA][lenB]);
    }
}
posted @ 2017-12-04 17:13  AlvinZH  阅读(331)  评论(0编辑  收藏  举报