【动态规划】【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个状态递推,才能满足没有后效性。

posted @ 2011-05-27 17:42  liukee  阅读(563)  评论(1编辑  收藏  举报