p1026
给出一个长度不超过200
200的由小写英文字母组成的字母串(约定;该字串以每行20个字母的方式输入,且保证每行一定为20个)。要求将此字母串分成k份(1<k≤40
1<k≤40),且每份中包含的单词个数加起来总数最大(每份中包含的单词可以部分重叠。当选用一个单词之后,其第一个字母不能再用。例如字符串this中可包含this和is,选用this之后就不能包含th)。
单词在给出的一个不超过6个单词的字典中。
要求输出最大的个数。
重叠条件 大概就是一个字母不能被两个或两个以上的单词作为首字母使用
理解这个就很好写的
先开个二位数组存区间i,j内有多少的合法的单词个数,这个的话就对于每个字母扫一遍,如果找到在字典中的首字母为这个单词,就直接把这个单词加进去,值得注意的是,倒序会好求一点,即r[i][j] = r[i][j-1]+1;
然后就dp方程了。。。
状态转移方程:f[i][j] = max(f[l][j-1]+r[l+1][I]);
1 <= l < I;
int p,k,siz,w[210][210],kl[10],dp[210][210],s;
char a[12][22],kk[10][210],dt[210];
int check(int d1,int d2) {
for(int i = 1;i <= kl[d1];i++) {
if(dt[d2+i-1] != kk[d1][i-1]) {
return 0;
}
}
return 1;
}
int del () {
for(int i = siz;i >= 1;i--) {
for(int j = i;j >= 1;j--) {
for(int l = 1;l <= k;l++) {
if(kl[l] <= i-j+1) {
if(check(l,j)) {
w[j][i]++;
break;
}
}
}
w[j][i] += w[j+1][i];
}
}
return 0;
}
int dynamic() {
for(int i = 1;i <= k;i++) {
dp[i][i] = dp[i-1][i-1] + w[i][i];
}
for(int i = 1;i <= siz;i++) {
dp[i][1] = w[1][i];
}
for(int i = 1;i <= siz;i++) {
for(int j = 2;j <= s;j++) {
for(int l = j;l < i;l++) {
dp[i][j] = max(dp[i][j],dp[l][j-1]+w[l+1][i]);
}
}
}
return 0;
}
int main () {
int sz = 1; //读入
scanf("%d%d",&p,&s); siz = p*20;
for(int i = 1;i <= p;i++) { scanf("%s",a[i]); }
scanf("%d",&k);
for(int i = 1;i <= k;i++) { scanf("%s",kk[i]); kl[i] = strlen(kk[i]); }
for(int i = 1;i <= p;i++) {
for(int j = 0;j <= 19;j++) {
dt[sz] = a[i][j]; sz++;
}
} //读入结束
del();//预处理
dynamic(); //求解
printf("%d",dp[siz][s]);
return 0;
}