【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;
}

posted @ 2016-07-19 21:20  Maxwei_wzj  阅读(227)  评论(0编辑  收藏  举报