题意:给出2个字符串x, y,长度为n,m,允许使用3种操作,求把x变成y需要的最小步骤,也就是要求两个字符串的编辑距离.
插入:在x的任意位置插入一个字符.
删除:在x的任意位置删除一个字符.
替换:在x的任意位置替换一个字符成任意字符.
设dp[i][j]为x后缀[i:]变成y的后缀[j:]所需要的最小步骤([i:]代表从i位置开始一直到尾部的字符串)
则:
如果x[i] == y[j],那么dp[i][j] = dp[i + 1][j + 1],不需要做任何操作.
如果x[i] != y[j],那么dp[i][j] = min(dp[i + 1][j + 1] + 1, dp[i][j + 1] + 1, dp[i + 1][j + 1] + 1).
解释下:
dp[i + 1][j + 1] + 1代表的是把x[i]替换成y[j],剩下的就是后缀[i + 1:]和后缀[j + 1:]的值了.
dp[i][j + 1] + 1代表的是在将y[j]插入到x[i]之前的位置,那么也就是剩下的后缀[i:]和后缀[j + 1:]的值了,因为y[j]和插入到x[i]之前的的字符抵消了.
dp[i + 1][j] + 1代表的删除x[i]位置的字符串,那么剩下也就是后缀[i + 1:]和后缀[j:]的值了,因为删除了x[i],在i后面的操作中总会出现和y[j]抵消掉的操作.
base cases:
dp[i][m] = n- i因为要把[i:]变成[M:]需要n-i次删除操作才能变空.
dp[n][j] = m-j同理.
#include <algorithm> #include <memory.h> #include <cstdio> using namespace std; const int MAX = 1001; #define min3(a, b, c) min((a), min((b), (c))) short dp[MAX][MAX]; char A[MAX], B[MAX]; int main(int argc, char const *argv[]){ int N, M; while(scanf("%d%s%d%s", &N, A, &M, B) == 4){ memset(dp, 0, sizeof(dp)); for(int i = 0; i < N; ++i){ dp[i][M] = N - i; } for(int j = 0; j < M; ++j){ dp[N][j] = M - j; } for(int i = N - 1; i >= 0; --i){ for(int j = M - 1; j >= 0; --j){ if(A[i] == B[j]){ dp[i][j] = dp[i + 1][j + 1]; }else{ dp[i][j] = min3(dp[i + 1][j + 1] + 1, dp[i][j + 1] + 1, dp[i + 1][j] + 1); } } } printf("%d\n", dp[0][0]); } return 0; }
POJ 3356 AGTC(经典DP Edit Distance),布布扣,bubuko.com
POJ 3356 AGTC(经典DP Edit Distance)
原文:http://blog.csdn.net/zxjcarrot/article/details/21289389