洛谷 P2453 [SDOI2006]最短距離
Description
Solution
乍一看,感覺還是挺難的,其實沒有那麼難,就是一個很暴力的 \(dp\)(我也不知道為什麼有狀壓的標籤)。
先定義一下 \(dp\) 狀態:設 \(dp[i][j]\) 表示目標串完成到第 \(i\) 個字元,源串刪除到第 \(j\) 個字元。
初始值:
\(dp[0][j] = cost_{delete} * j\)
\(dp[i][0] = cost_{insert} * i\)
嗯,很顯然。
下面我們來分析一下每個操作。
insert
插入操作:\(dp[i][j] = min(dp[i][j], dp[i - 1][j] + cost_{insert})\)
不需要進行判斷。
delete
刪除操作;\(dp[i][j] = min(dp[i][j], dp[i][j - 1] + cost_{delete}\)
很容易想到吧,且這個操作同樣無需判斷。
replace
替換操作:\(dp[i][j] = min(dp[i][j], dp[i - 1][j - 1] + cost_{replace})\)
顧名思義,都要進行替換了,還判斷什麼呢?
copy
複製操作:\(dp[i][j] = min(dp[i][j], dp[i - 1][j - 1] + cost_{copy})\)
這個就需要進行判斷了,當源串 \(x_j\) 等於目標串 \(y_i\)
twiddle
交換並複製,這個就有點麻煩了。
先判斷,當 \(i\) 和 \(j\) 都大於 1,且 \(x_j == y_{i - 1}\) && \(y_i == x_{j - 1}\)時,才能進行轉移。
轉移方程:\(dp[i][j] = min(dp[i][j], dp[i - 2][j - 2] + cost_{twiddle})\)
kill
刪除一段字元。
這個怎麼轉移呢?
很簡單,單獨拎出來就好了。
最後再列舉一遍源串,然後對 \(dp[leny][i] + cost_{kill}\) 取個 \(min\) 即可。
輸出的時候再和 \(dp[leny][lenx]\)
Code
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
char a[1010], b[1010];
int del, rep, cop, ins, twi;
int dp[210][210];
int main(){
scanf("%s%s", a + 1, b + 1);
int la = strlen(a + 1);
int lb = strlen(b + 1);
scanf("%d%d%d%d%d", &del, &rep, &cop, &ins, &twi);
memset(dp, 127, sizeof(dp));
dp[0][0] = 0;
for(int i = 1; i <= la; i++)
dp[0][i] = del * i;
for(int i = 1; i <= lb; i++)
dp[i][0] = ins * i;
for(int i = 1; i <= lb; i++)
for(int j = 1; j <= la; j++){
dp[i][j] = min(dp[i][j], dp[i][j - 1] + del);
dp[i][j] = min(dp[i][j], dp[i - 1][j - 1] + rep);
if(a[j] == b[i])
dp[i][j] = min(dp[i][j], dp[i - 1][j - 1] + cop);
dp[i][j] = min(dp[i][j], dp[i - 1][j] + ins);
if(i > 1 && j > 1 && a[j] == b[i - 1] && b[i] == a[j - 1])
dp[i][j] = min(dp[i][j], dp[i - 2][j - 2] + twi);
}
int ans = 0x7fffffff;
for (int i = 1; i < la; i++)
ans = min(ans, dp[lb][i] + (la - i) * del - 1);
ans = min(ans, dp[lb][la]);
printf("%d\n", ans);
return 0;
}
End
本文來自部落格園,作者:{xixike},轉載請註明原文連結:https://www.cnblogs.com/xixike/p/15168082.html