題目大意
給出一個主串,和一本字典,問最少在主串刪除多少字母,可以使其匹配到字典的單詞序列。
是匹配單詞序列,而不是一個單詞
思路分析
主要是知道狀態方程的含義
dp[i]
表示從message中第i
個字符開始,到第L
個字符(結尾處)這段區間所刪除的字符數,初始化爲 dp[L]=0
由於我的程序是從message尾部向頭部檢索匹配,所以是下面的狀態方程:
if(和字典中的某長度爲len的字符匹配成功)dp[i]=min(dp[i],dp[pm]+(pm-i)-len);
else dp[i]= dp[i+1]+1
從程序可以看出,第i
個位置到L
所刪除的字符數,總是先取最壞情況,只有可以匹配單詞時才進入第二條方程進行狀態優化更新。
第一條方程不難理解,只要弄懂 dp[i]
的意義就能簡單推導
第二條方程難點在 dp[pm]+(pm-i)-len
從程序知道,pm
是message的指針(其中i
表示當前所匹配的單詞在message中的起始位置),pd
是字典的指針
匹配的過程是:
當確認message第i
位和某單詞的首位吻合時,就開始逐字匹配,字符相同則兩個指針同時向後移動一次,否則pd
固定,pm
移動。當因爲 pm>L
跳出匹配時,說明匹配失敗,dp[i]
狀態不變;當 pd==單詞長度
時,單詞匹配成功,進行 dp[i]
的狀態優化。
顯然,匹配成功時,pm-i
代表匹配過程中,從位置i
到pm
的區間長度,再減去單詞長度len
,則得到從i
到pm
所刪除的字符數(pm-i)-len
。又 dp[pm]
表示從pm
到L
所刪除的字符數(根據檢索方向,dp[pm]
的值在此前已經被作爲最壞打算處理,因此並不是空值)
從而 dp[pm]+(pm-i)-len
表示i
到L
刪除的字符數,不難證明這個值一定比 dp[i]
相等或更優,因此取min
賦值給 dp[i]
。
這是本題最難的地方。
最後輸出 dp[0]
就可以了,dp[0]
的意思相信大家都明白了。
#define inf 0x3f3f3f3f
#define vec vector<int>
#define P pair<int,int>
#define ll long long
#define MAX 605
int dp[305], W, L;
string s[MAX], t;
int main() {
while (scanf("%d %d", &W, &L) != EOF) {
cin >> t;
for (int i = 0; i < W; i++)cin >> s[i];
memset(dp, 0, sizeof(0));
for (int i = L - 1; i >= 0; i--) {//對每一位進行判斷
dp[i] = dp[i + 1] + 1;
for (int j = 0; j < W; j++) {//對字典的每一個串進行判斷
int len = s[j].size();
if (L - i >= len && s[j][0]==t[i]) {
//這一個串可能可以匹配上
int i1 = i, i2 = 0;
while (i1 < L&&i2 < len) {
if (t[i1] == s[j][i2])i2++;
i1++;
}
if (i2 == len)//匹配上了
dp[i] = min(dp[i], dp[i1] + i1 - i - len);
}
}
}
cout << dp[0] << endl;
}
}