线性DP——POJ 3276

线性DP——POJ 3276

问题

给定你一个字符串,和n个单词构成的字典。让你求出在字符串中最小删去几个字母,使得剩下的字符串能够由字典中的若干个单词构成。输出最少删去的字母的个数。


分析
考虑给定字符串中第i个字符,可能删去,可能保留。——定义划分状态的关键。
d[i]=Min{d[i-1]+1,make(i)}//delete vs not delete

如果不删去,则它一定是作为某个单词的末尾。故与该位置前的状态有关系。make(i)中,要比较,所有字典中以msg[i]结尾的单词:若要保留,则此过程中删去字母个数ct,return 就是Min{d[该单词首字母的前一个字符位置]+ct}
#include < cstdio >
#include
< cstring >
#include
< cmath >
#include
< cstdlib >
#define  INF 1000000
#define  MIN(a,b) (a)>(b)?(b):(a)
int  N,L;
char  dic[ 600 ][ 26 ],msg[ 305 ];
int  f[ 305 ]; // 记录第i位前丢弃的最少字母数

int  make( int  m)
{
    
int k,j,ct=0,n=m,t,re=INF;
    
for(k=0;k<N;++k)
    
{
        
if(dic[k][strlen(dic[k])-1]==msg[m])//若写m为n此处n=0,WA
        {
            n
=m;ct=0;
            j
=strlen(dic[k])-1;
            
            
while(j>=0)
            
{
                
while(n>=0&&msg[n]!=dic[k][j])
                
{
                    n
--;
                    ct
++;
                }

                
if(n>=0&&msg[n]==dic[k][j])n--;//当n小于0时说明此单词比该msgd第n位前的字串长
                else break;
                j
--;
            }

            
//if(j==-1&&ct+f[n-1]<re)
            
//{
            
//    re=ct+f[n-1];
            
//    //t=n;
            
//}
            if(j==-1)//说明字典中存在以msg【n】结尾的子串=该单词
            {
                
if(n>=0&&ct+f[n]<re)//由于上一个if语句多减了一次1,所以此时perhaps n<0
                    re=ct+f[n];
                
else if(n<0&&ct<re)re=ct;//此时说明msg中的该单词恰好是从msg[0]开始的
            }

        }

    }

    
/**//*if(re==INF)头开始误导了,想着总是加一,不对。其实是对的,会自己判断选择到达该状态的其他路径,
        return f[m-1]==0?0:f[m-1]+1;                                故此处多余
*/

        
    
return re;
}

int  main()
{
    
int len,i,j,k;
    scanf(
"%d",&N);
    scanf(
"%d",&len);
    scanf(
"%s",msg);
    
//for(i=0;i<len;i++)调试时的代码一定要记得注释掉!!!WA两次因此。太suck了
    
//    printf("%c ",msg[i]);
    
//printf("\n");
    
//for(i=0;i<len;i++)
    
//    printf("%-2d",i);
    
//printf("\n");
    for(i=0;i<N;++i)
    
{
        scanf(
"%s",dic[i]);
    }

    len
=strlen(msg);
    f[
0]=1;//初始状态可能不为1,即第一个字符也可能作为字典单词的最后一个字母,此时该单词位单字母单词
    for(i=0;i<N;++i)
        
if(strlen(dic[i])==1&&dic[i][0]==msg[0])f[0]=0;
    
for(i=1;i<len;i++)
    
{
        f[i]
=MIN(f[i-1]+1,make(i));
    }

    printf(
"%d\n",f[len-1]);
    
}


你可能感兴趣的:(线性DP——POJ 3276)