1. 程式人生 > 其它 >P2758 編輯距離做題筆記

P2758 編輯距離做題筆記

這題是昨天做的,寫到一半打模擬賽了,斷了網,沒有存,順帶吐槽洛谷部落格沒有草稿箱,再加上今天上午也有模擬賽,所以咕咕咕到了現在才來寫做題筆記。開始看題時一臉懵逼,可能是因為平時做 dp 題想太少且看題解太多的原因吧,經常想不出狀態轉移方程,只好看來題解,題解裡有兩種做法,一種遞迴,一種遞推,由於遞迴過於罕見,就選擇了自己比較熟悉的遞推,具體思路是用 \(s_{i,j}\) 表示 a 序列的 1 到 i 部分變成 b 序列的 1 到 j 部分至少需要幾次操作。狀態轉移方程: \(s_{i,j}\) 可以從 \(s_{i-1,j}\)\(s_{i,j-1}\)\(s_{i-1,j-1}\)

推出,若 \(a_i = b_j\)\(s_{i,j} = s_{i-1,j-1}\),因為新加的 \(a_i\)\(b_j\) 之間無需轉換,否則需要轉換一次,狀態轉移方程為:\(s_{i,j} = min(s_{i-1,j},s_{i,j-1},s_{i-1,j-1})+1\)

#include <bits/stdc++.h>
  using namespace std;
char c[3005],d[3005];
int n,m,s[3005][3005],i,j;
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	cin>>c+1>>d+1;
	n=strlen(c+1);
	m=strlen(d+1);
	for (i=1;i<=n;i++)
	{
		s[i][0]=i;
	}
	for (i=1;i<=m;i++)
	{
		s[0][i]=i;
	}
	for (i=1;i<=n;i++)
	{
		for (j=1;j<=m;j++)
		{
			if (c[i]==d[j]) s[i][j]=s[i-1][j-1];
			else s[i][j]=min(s[i-1][j-1],min(s[i][j-1],s[i-1][j]))+1;
		}
	}
	cout<<s[n][m]<<endl;
	return 0;
}