codevs【1040】统计单词个数

题目描述
给出一个长度不超过200的由小写英文字母组成的字母串(约定;该字串以每行20个字母的方式输入,且保证每行一定为20个)。要求将此字母串分成k份(1 单词在给出的一个不超过6个单词的字典中。
要求输出最大的个数。

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

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

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

样例输出
7

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

#include
#include
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;
} 

你可能感兴趣的:(划分型动态规划,codevs,统计单词个数)