POJ 3267 The Cow Lexicon【题解报告|DP】

题目链接

题目大意

给出一个主串,和一本字典,问最少在主串删除多少字母,可以使其匹配到字典的单词序列。

是匹配单词序列,而不是一个单词

思路分析

主要是知道状态方程的含义

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 代表匹配过程中,从位置ipm的区间长度,再减去单词长度len,则得到从ipm所删除的字符数(pm-i)-len 。又 dp[pm] 表示从pmL所删除的字符数(根据检索方向,dp[pm]的值在此前已经被作为最坏打算处理,因此并不是空值)

从而 dp[pm]+(pm-i)-len 表示iL删除的字符数,不难证明这个值一定比 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;
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章