題意:
給你兩個DNA序列,長度小於1000 ,同時定義了三種編輯操作:1. 將任意一個字符刪除 2. 在任意位置添加一個字符 3. 將任意一個字符替換成令一個字符。
問:將第一個DNA序列變成第二個最少需要多少次操作。
解法:
經典DP問題,編輯距離,模板題, O(n2)。
狀態:
dp[i][j] 表示由前一個字符串的前i個變成後一個字符串的前j個字符所需的最少次數。
轉移方程:
a[i] == b[j] -> dp[i][j] = min(dp[i-1][j]+1, dp[i][j-1]+1, dp[i-1][j-1])
a[i] != b[j] -> dp[i][j] = min(dp[i-1][j]+1, dp[i][j-1]+1, dp[i-1][j-1]+1)
dp[i-1][j]轉移來的含義是在a的當前位置插入一個字符,d[i][j-1]則是要在a的當前字符刪掉,dp[i-1][j-1]轉移來則是要進行字符替換,若當前的兩個字符相等,操作便不會增加,轉移的結果取最少的。
初始化:
dp[i][0] = i , dp[0][j] = j
由於任何空串轉化成別的串一定要進行串長度次添加,同理,變爲空串需要一定步數的刪除操作。
代碼:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <string>
#include <stack>
#include <queue>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn = 1e3+5;
int dp[maxn][maxn];
int main(){
string a,b;
int la,lb;
while(cin >> la >> a){
cin >> lb >> b;
a = "$" + a;
b = "$" + b;
memset(dp, 0 , sizeof(dp));
for(int i = 0 ; i <= la ; i++){
dp[i][0] = i;
}
for(int j = 0 ; j <= lb ; j++){
dp[0][j] = j;
}
for(int i = 1 ; i <= la ; i++){
for(int j = 1; j <= lb ; j++) {
dp[i][j] = min(dp[i-1][j]+1, min(dp[i][j-1]+1, dp[i-1][j-1]+(a[i]!=b[j])));
}
}
cout << dp[la][lb] << endl;
}
return 0;
}