洛谷P1026统计单词个数题解--zhengjun

题目描述

给出一个长度不超过 200 200 的由小写英文字母组成的字母串(该字串以每行 20 20 个字母的方式输入,且保证每行一定为 20 20 个)。要求将此字母串分成 k k 份,且每份中包含的单词个数加起来总数最大。

每份中包含的单词可以部分重叠。当选用一个单词之后,其第一个字母不能再用。例如字符串 this 中可包含 thisis,选用 this 之后就不能包含 th

单词在给出的一个不超过 6 6 个单词的字典中。

要求输出最大的个数。

输入格式

每组的第一行有两个正整数 p , k p,k p p 表示字串的行数, k k 表示分为 k k 个部分。

接下来的 p p 行,每行均有 20 20 个字符。

再接下来有一个正整数 s s ,表示字典中单词个数。 接下来的 s s 行,每行均有一个单词。

输出格式

1 1 个整数,分别对应每组测试数据的相应结果。

输入输出样例

输入 #1 复制
1 3
thisisabookyouareaoh
4
is
a
ok
sab
输出 #1 复制
7

说明/提示

【数据范围】

对于 100 % 100\% 的数据, 2 k 40 2 \le k \le 40 1 s 6 1 \le s \le 6

【样例解释】

划分方案为 t h i s / i s a b o o k y o u a / r e a o h this / isabookyoua / reaoh

思路

首先,这是一道有点难度的动态规划。
f i , j f_{i,j} 表示 从尾巴用了 i i 个字符分了 j j 段的最多有多少个单词。
则转移方程不难想到:
f i , j = m a x ( f i , j , f l , j 1 + s u m l + 1 , i ) f_{i,j}=max(f_{i,j},f_{l,j-1}+sum_{l+1,i})
s u m sum 就是从 j j i i 的单词个数
然后 s u m sum 就可以在前面预处理暴力算出来

代码

#include<bits/stdc++.h>
using namespace std;
int p,n,m,k,f[210][50],sum[210][210];
string s,a[10];
bool check(int l,int r){
    string x=s.substr(l,r-l+1);//这个函数就是返回字符串s从第l个字符开始后面的r-l+1个字符所组成的字符串
    for(int i=1;i<=n;i++)
	     if(x.find(a[i])==0)//这个函数可以返回a[i]在x中最早出现的位置
		     return 1;
    return 0;
}
int main(){
    string ch;
    s+='0';
    cin>>p>>k;
    for(int i=1;i<=p;i++){
        cin>>ch;
        s+=ch;
    }
    cin>>n;
	m=s.length()-1;
    for(int i=1;i<=n;i++)
		cin>>a[i];
    for(int i=m;i>=1;i--)
    	for(int j=i;j>=1;j--){
    	    sum[j][i]=sum[j+1][i];
   	        if(check(j,i))
			    sum[j][i]++;
   		}
    f[0][0]=0;
    for(int i=1;i<=k;i++)
		f[i][i]=f[i-1][i-1]+sum[i][i];
    for(int i=1;i<=m;i++)
		f[i][1]=sum[1][i];
    for(int i=1;i<=m;i++)
    	for(int j=1;j<=k&&j<i;j++)
    		for(int k=j;k<i;k++)
    			f[i][j]=max(f[i][j],f[k][j-1]+sum[k+1][i]);
    printf("%d",f[m][k]);
    return 0;
}

谢谢–zhengjun

发布了48 篇原创文章 · 获赞 49 · 访问量 2143

猜你喜欢

转载自blog.csdn.net/A_zjzj/article/details/104677135