题意就是给出一个主串,和一本字典,问最少在主串删除多少字母,可以使其匹配到字典的单词序列。
最开始的dp方程:
dp[j][i] 表示字符串从0到j这个区间内是否用第i个单词组成
dp[j][i]=min(dp[j-1][i-1]+1,dp[p][i-1]+j-p-len[i]); p表示第i个单词揉进字符串0....j最近的位置,len[i]表示单词长度
循环是 外层 i,里层 j
送了几发wa后发现
还是这个方程,可以把i去掉 : dp[j]=min(dp[j-1]+1,dp[p]+j-p-len[i]);
那么含义就成了 第j个字符是删或不删
删:dp[j]=dp[j-1]+1;
不删: 能从单词表中查询到 dp[j]=min(dp[p]+j-p-len[i]);
循环是外层j ,里层 i
//给你一个主串,和一些单词,
//问你在主串中至少删除几个字母,剩下的都是由给出的单词组成。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_W 605
#define MAX_L 305
#define INF 0x3f3f3f3f
#define find_min(a,b) a>b?b:a
int w,l;
int dp[MAX_L];
int len[MAX_W];
char str[MAX_W][100];
char input[MAX_L];
int find(int r,int len,char *s)
{
int p=r,k=len;
while(p>=0&&k)
{
if(s[k-1]==input[p])
--k;
--p;
}
return p;
}
int solve()
{
for(int i=1;i<=w;++i)
len[i]=strlen(str[i]);
dp[0]=0;
for(int j=1;j<=l;++j)
{
dp[j]=dp[j-1]+1;
for(int i=1;i<=w;++i)
{
if(len[i]<=j)
{
int p=find(j,len[i],str[i]);
// printf("%d %d %d %d\n",j,len[i],i,p);
if(p!=-1)
{
dp[j]=find_min(dp[j],dp[p]+j-p-len[i]);
}
}
}
}
return dp[l];
}
int main()
{
input[0]='#';
while(~scanf("%d%d",&w,&l))
{
scanf("%s",input+1);
for(int i=1;i<=w;++i)
scanf("%s",&str[i]);
printf("%d\n",solve());
}
return 0;
}