codevs【1040】统计单词个数

题目描述
给出一个长度不超过200的由小写英文字母组成的字母串(约定;该字串以每行20个字母的方式输入,且保证每行一定为20个)。要求将此字母串分成k份(1<k<=40),且每份中包含的单词个数加起来总数最大(每份中包含的单词可以部分重叠。当选用一个单词之后,其第一个字母不能再用。例如字符串this中可包含this和is,选用this之后就不能包含th)。
单词在给出的一个不超过6个单词的字典中。
要求输出最大的个数。

输入描述
第一行为一个正整数(0<n<=5)表示有n组测试数据
每组的第一行有二个正整数(p,k)
p表示字串的行数;
k表示分为k个部分。
接下来的p行,每行均有20个字符。
再接下来有一个正整数s,表示字典中单词个数。(1<=s<=6)
接下来的s行,每行均有一个单词。

输出描述
每行一个整数,分别对应每组测试数据的相应结果。

样例输入
1
1 3
thisisabookyouareaoh
4
is
a
ok
sab

样例输出
7

分析
这道题属于划分型的动态规划,首先要获得不同区间内单词的数目,采用二维数组a进行存储,然后再进行划分。

#include<iostream>
#include<cstring>
using namespace std;
#define N 200 + 10 
int a[N][N],dp[N][N];
//a[i][j]表示i到j之间有多少个单词
//dp[i][j]中i表示前i+1(i从0开始)个字符,j表示j次划分
string w[100];
int main()
{
	int T;
	cin >> T;
	int p,K,s;
	string t;
	while(T--) {
		cin >> p >> K;
		string tmp;
		t = "";
		memset(a,0,sizeof(a));
		memset(dp,0,sizeof(dp));
		for(int i = 0; i < p; i++) {
			cin >> tmp;
			t += tmp;//把一行一行字符串拼接成一串
		}
		cin >> s;
		for(int i = 0; i < s; i++)
			cin >> w[i];

		for(int i = 0; i < t.size(); i++)//从i的位置向前找
			for(int j = i; j >= 0; j--) {
				a[j][i] = a[j + 1][i];
				for(int k = 0; k < s; k++) {
					if(w[k].size() <= (i - j + 1)) {
						int n = 0,m = j;
						//判断是否为单词
						while(w[k][n] && w[k][n] == t[m]) {
							n++;
							m++;
						}
						if(n == w[k].size()) {
							a[j][i]++;
							break;
						}
					}
				}
			}

		for(int i = 0; i < t.size(); i++)
			dp[i][0] = a[0][i];//前i+1个字符分成一份 
		
		for(int i = 0; i < t.size(); i++)
			for(int j = 1; j < K; j++)//划分的次数
				for(int k = j - 1; k < i; k++)//至少为j份才可以进行j-1次划分 
					dp[i][j] = max(dp[i][j],dp[k][j - 1] + a[k + 1][i]);
		
		cout << dp[t.size() - 1][K - 1] << endl;//这里K-1是因为划了K-1次 
	}
	return 0;
} 
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值