【NOIP2001提高组T3】统计单词个数-字符串上的动态规划
(本人本题完成于2016-7-19)
题目大意:给定一个字符串(长度为20*p,不超过200)和一个包含一些单词(个数为n,1≤n≤6)的词典,问如何将该字符串分成K(不超过40)份,使得每份中包含的单词个数之和最大,输出这个最大值。以一个位置为起始点只能统计一个单词。
做法:用a[i][j]表示区间(i,j)内所含的单词个数,可以用暴力计算出所有a[i][j]。再设f[i][j]为字符串前i个字符分割成j份的最优解,最终答案即是f[20*p][K]。状态转移方程为:f[i][j]=max(f[i][j],f[k][j-1]+a[k+1][i])。
以下是本人代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
long p,K,n,a[210][210]={0},f[210][210]={0}; //a,f的意义如上文所示
char w[10][210],s[210]; //w存储词典,s存储待处理的字符串
bool v[210]={0}; //v[i]表示当前以i为起始位置有没有统计过单词,值为1时代表已统计过
int main()
{
scanf("%ld %ld\n",&p,&K);
for(int i=1;i<=p;i++)
{
for(int j=(i-1)*20+1;j<=i*20;j++)
scanf("%c",&s[j]);
scanf("\n");
}
scanf("%ld\n",&n);
for(int i=1;i<=n;i++)
{
scanf("%s\n",w[i]);
for(int j=1;j<i;j++)
if (!strcmp(w[i],w[j])) {i--;n--;break;} //比较,如果当前单词与已输入单词重复则舍去当前单词
}
for(int i=1;i<=20*p;i++)
for(int j=i;j<=20*p;j++)
{
memset(v,0,sizeof(v));
for(int k=1;k<=n;k++)
{
long len=strlen(w[k]);
for(int ii=i;ii<=j-len+1;ii++)
{
if (v[ii]) continue;
bool flag=1;
for(int jj=0;jj<len;jj++)
if (s[ii+jj]!=w[k][jj]) {flag=0;break;}
if (flag) {a[i][j]++;v[ii]=1;}
}
}
} //暴力求出所有a[i][j]
for(int k=1;k<=K;k++)
for(int i=1;i<=20*p;i++)
for(int j=k-1;j<=i-1;j++) //注意从k-1开始,勿漏情况
f[i][k]=max(f[i][k],f[j][k-1]+a[j+1][i]);
printf("%ld",f[20*p][K]);
return 0;
}