【动态规划】【poj 3267】The Cow Lexicon
问题
给定你一个字符串,和n个单词构成的字典。让你求出在字符串中最小删去几个字母,使得剩下的字符串能够由字典中的若干个单词构成。输出最少删去的字母的个数。
分析
如果考虑第i位的字母,当然只有要和不要两种状态,这是本题的突破口,是划分状态的根本。f[i]表示到第i位最少需要删除的字母的数目。那么得到如下的方程:f[i]:=min{f[i-1]+1,make(i)}不要当前的字母自然不需要解释,直接由相邻的状态更新,无后效性。如果要保留第i位,就需要函数解决。因为第i位的保留就必须有单词能够保留住它,也就会影响和它相邻的状态。当然不能简单地推。
至于make函数,如果要保留s[i],必有单词的最后一位恰好为s[i],所以枚举单词,在枚举如果用这个单词需要从该位开始删去前面的几个字母,到达什么位置。
显然make(i)=min{f[j](到达的位置)+该过程删去的字母}
code
program liukee; var n,len,i,temp:longint; s:ansistring; word:array[1..650] of string; f:array[0..400] of longint; procedure init; var i:longint; begin readln(n,len); readln(s); minlen:=maxlongint; for i:=1 to n do begin readln(word[i]); if word[i]<minlen then minlen:=word[i]; end; end; function make(k:longint):longint; var i,j,p,x:longint; begin make:=maxlongint; if k<minlen then exit(maxlongint); for i:=1 to n do if s[k]=word[i][length(word[i])] then begin j:=k; p:=length(word[i]); while j>0 do begin if s[j]=word[i][p] then dec(p); dec(j); if p=0 then break; end; if p<>0 then continue; x:=k-j-p+f[j]; if x<make then make:=x; end; end; begin init; f[0]:=0; for i:=1 to len do begin temp:=make(i); if temp<f[i-1]+1 then f[i]:=f[i-1]+1 else f[i]:=temp; end; writeln(f[n]); end.
反思
f[i]=min(max){f[i-1],function(i)}这是一类问题,要先找到第i个状态的转移。但该方程不和一般动归一样是由邻近的的状态更新来的,第i个状态的转移需要由第i-k个状态递推,才能满足没有后效性。