zoukankan      html  css  js  c++  java
  • codevs1040统计单词个数(区间+划分型dp)

    1040 统计单词个数

     

    2001年NOIP全国联赛提高组

     时间限制: 1 s
     空间限制: 128000 KB
     题目等级 : 黄金 Gold
     
    题目描述 Description

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

    输入描述 Input Description

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

    输出描述 Output Description

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

     

    样例输入 Sample Input

    1
    1 3
    thisisabookyouareaoh
    4
    is
    a
    ok
    sab

    样例输出 Sample Output

    7

    /*
    每读取一行可以用strcat把字符串连在一起
    从字符串A中搜索单词word可以用char *p=strstr(A,word);
    返回NULL则找不到,顺带可以用p-A==0来判断单词是否从A[0]开始匹配。
    先预处理出w[i][j],表示从i到j的单词数。可以倒着推,w[i][j]=w[i+1][j];
    (如果存在从A[i]字母开始的单词,则w[i][j]=w[i+1][j]+1.出现同一字母开头的多个单词也还是加1就够了.)
    F[i][j]表示前i个字母分成j段得到的最大单词数,答案是F[len][k],
    可以初始化一下F[i][i]和F[i][1]. 方程F(i,j)=max{ F(r,j-1)+w(r+1,i) (r=j...i-1) }. 
    意思就是把1..r的字母先分成j-1段,剩下的r+1..i的字母分成另一段。
    */
    
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    
    using namespace std;
    int p,k,s,len,w[2005][2005],f[2005][450];
    char A[2050],str[250],Word[100][2005];
    
    void Input()
    {
        scanf("%d%d",&p,&k); len=20*p;
        while(getchar()!='
    ');
        while(p--)
        {
            scanf("%s",str);
            strcat(&A[1],str);
        }
        scanf("%d",&s);
        while(getchar()!='
    ');
        for(int i=1;i<=s;i++) cin>>Word[i];
    }
    
    int have(int x,int end)
    {
        for(int i=1;i<=s;i++)
        {
            char *p=strstr(&A[x],Word[i]);
            if(p!=NULL && p-&A[x]==0 
                && strlen(Word[i])<=end-x+1) return 1;
        }
        return 0;
    }
    
    void Init()
    {
        for(int j=len;j>0;j--)
          for(int i=j;i>0;i--)
            if(have(i,j)) w[i][j]=w[i+1][j]+1;
            else w[i][j]=w[i+1][j];
    }
    
    void DP()
    {
        for(int i=1;i<=k;i++) f[i][i]=f[i-1][i-1]+w[i][i];
        for(int i=1;i<=len;i++) f[i][1]=w[1][i];
        for(int i=1;i<=len;i++)
          for(int j=2;j<=k && j<=i;j++)
            for(int r=j;r<i;r++)
              f[i][j]=max(f[i][j],f[r][j-1]+w[r+1][i]);
    }
    
    int main()
    {
        int t;
        cin>>t;
        while(t--)
        {
            Input();
            Init();
            DP();
            printf("%d",f[len][k]);
        }
        return 0;
    }
    心若向阳,无谓悲伤
    折花枝,恨花枝,准拟花开人共卮,开时人去时。 怕相思,已相思,轮到相思没处辞,眉间露一丝。
  • 相关阅读:
    461. Hamming Distance
    342. Power of Four
    326. Power of Three
    368. Largest Divisible Subset java solutions
    95. Unique Binary Search Trees II java solutions
    303. Range Sum Query
    160. Intersection of Two Linked Lists java solutions
    88. Merge Sorted Array java solutions
    67. Add Binary java solutions
    14. Longest Common Prefix java solutions
  • 原文地址:https://www.cnblogs.com/L-Memory/p/6351777.html
Copyright © 2011-2022 走看看