//题意:给一个母串,给一些单词,这个母串有下面一些单词组成,问最少删减几个字符,就可由一些单词组成母串
//思路:dp[i]表示当前下表位置的串最少删掉的字符个数,那么将单词分别与母串比较,母串从前向后从第一个字符开始比较,若单词长度大于当前母串下标则dp[i] = dp[i-1] + 1,当单词长度大于等于当前母串下表时,若此时正好完全包含某个单词,那么d[i] = dp[i-len] + (i-p1) - len + 1; len表示当前单词的长度;p1表示当前单词开始下标;dp[i-len]当前单词开始标前的最小删除个数;(i-p1) - len + 1 表示从单次开始到单词结束可以删的字符。
dp[i] = dp[i-1] + 1;
d[i] = dp[i-len] + (i-p1) - len + 1; 解决母串由多个单词组成时的解决方案(由于要知道每次单词开始的下标方便的方法是倒着遍历单词)
#include<cstdio>
#include<cstring>
#include <algorithm>
using namespace std;
#define inf 0x3f3f3f3f
char s1[333],s2[666][30];
int dp[333];
int main()
{
int n,m,p,min1,p1;
while(~scanf("%d%d",&n,&m))
{
scanf("%s",s1+1);
for(int i = 0; i<n; i++){
scanf("%s",s2[i]);
}
dp[0] = 0;
for(int i =1; i<=m; i++){
min1 = inf;
for(int j =0; j<n; j++){
int len = strlen(s2[j]);
p = len-1;
if(len <= i){
for(int k = i;k>=1;k--){ //方便记录单词开始位置则采用倒序遍历
if(s1[k] == s2[j][p]){
p--;
if(p == -1){
p1 = k;
break;
}
}
}
}
if(p == -1){
min1 = min(min1,(i-p1)-len+1+dp[p1-1]);
}
}
dp[i] = min(dp[i-1]+1,min1);
}
printf("%d\n",dp[m]);
}
return 0;
}