统计单词个数
Description
给出一个长度不超过200的由小写英文字母组成的字母串(约定;该字串以每行20个字母的方式输入,且保证每行一定为20个)。要求将此字母串分成k份(1<k≤40),且每份中包含的单词个数加起来总数最大(每份中包含的单词可以部分重叠。当选用一个单词之后,其第一个字母不能再用。例如字符串this中可包含this和is,选用this之后就不能包含th)。 单词在给出的一个不超过6个单词的字典中。要求输出最大的个数。
Input
第一行有2个正整数p,k。p表示字串的行数;k表示分为k个部分。
接下来的p行,每行均有20个字符。
再接下来有一个正整数s,表示字典中单词个数。(1≤s≤6)
接下来的s行,每行均有一个单词。
Output
仅一行,一个整数,表示划分出来的最多单词个数。
Sample Input
1 3
thisisabookyouareaoh
4
is
a
ok
sab
Sample Output
7
Hint
按如下方式划分字符串:
this/isabookyoua/reaoh
题解:
dp[i][t] 代表前 i 个字母分成 t 段的最大单词数。1<=t<=k
w[i][j] 代表 区间[i,j]的最大单词数。
先求出 w, 再求 dp。
w[i][j] 不能共同前缀, 所以从后往前更新,验证前缀。
w[i][j] = w[i+1][j]+1 (当存在以i开头的单词完全在 [i,j] 内)
w[i][j] = w[i+1][j] 不存在
然后 dp[i][t] = max(dp[i][t], dp[j][t-1]+w[j+1][i]);
#include<stdio.h>
#include<string.h>
#define max(a,b) a>b?a:b
char s[200],word[7][200];
int dp[200][200],w[200][200],p,k,n,wordlen[7];
int check(int i,int j){//检查开头新加字母s[i]区间[i,j]单词是否加一
int k;
for(k=0;k<n;k++){
if((memcmp(word[k],s+i,wordlen[k])==0)&& (wordlen[k]<=(j-i+1))){
return 1;
}
}
return 0;
}
void calw(){//求w[i][j]
int i,j;
for(j==p*20-1;j>=0;j--){
w[j][j]=check(j,j);
for(i=j-1;i>=0;i--){
w[i][j]=w[i+1][j]+check(i,j);
}
}
}
void caldp(){//动态规划
int i,j,t;
for(i=0;i<p*20;i++){
dp[i][1]=w[0][i];
}
for(t=2;t<=k;t++){
for(i=t-1;i<p*20;i++){
for(j=t-1;j<i;j++){
dp[i][t]=max(dp[i][t],dp[j][t-1]+w[j+1][i]);
}
}
}
}
int main(){
int i,j;
scanf("%d%d",&p,&k);
for(i=0;i<p;i++){
scanf("%s",s+i*20);
}
scanf("%d",&n);
for(i=0;i<n;i++){
scanf("%s",word[i]);
wordlen[i]=strlen(word[i]);
}
calw();//求w[i][j]
caldp();//动态规划
printf("%d",dp[p*20-1][k]);
}