统计单词个数

统计单词个数

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]); 
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值