zoukankan      html  css  js  c++  java
  • [luogu]P1026 统计单词个数[DP][字符串]

    [luogu]P1026

    统计单词个数

    题目描述

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

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

    要求输出最大的个数。

    输入输出格式

    输入格式:

    每组的第一行有二个正整数(p,k)

    p表示字串的行数;

    k表示分为k个部分。

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

    再接下来有一个正整数s,表示字典中单词个数。(1<=s<=6)

    接下来的s行,每行均有一个单词。

    输出格式:

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

    输入输出样例

    输入样例1#:

    1 3
    thisisabookyouareaoh
    4
    is
    a
    ok
    sab

    输出样例1#:

    7

    说明

    this/isabookyoua/reaoh


    看到这题先想到dp,及其转移方程:

    f[i][k]=Max{f[j][k-1],s[j+1][i]}(i为位置,k为次数,s为区间单词数)

    注意到一个单词被用过后首字母不能再用,所以如果(j,i)区间以j为首存在单词,则:s[j][i]=s[j+1][i]+1 否则s[j][i]=s[j+1][i]

    注意边界,f[i][k](i<k不存在,不能由其转移,否则gg,惨痛的教训...)

    代码:

     1 //2017.11.7
     2 //DP
     3 #include<iostream>
     4 #include<cstdio>
     5 #include<cstring>
     6 using namespace std;
     7 int Max(int x,int y){return x>y?x:y;}
     8 namespace lys{
     9     char s[256],c[10][256];
    10     int num[256][256],dp[256][50];
    11     int p,K,n;
    12     bool exist(int x,int y){
    13         int l=y-x+1;
    14         int i,j,k;
    15         for(i=0;i<n;i++){
    16             if(strlen(c[i])>l) continue ;
    17             k=x;
    18             for(j=0;j<strlen(c[i]);j++) if(c[i][j]!=s[k++]) break ;
    19             if(j==strlen(c[i])) return true ;
    20         }
    21         return false ;
    22     }
    23     int main(){
    24         int i,j,k;
    25         scanf("%d%d",&p,&K);
    26         for(i=0;i<p;i++) scanf("%s",s+i*20);
    27         scanf("%d",&n);
    28         for(i=0;i<n;i++) scanf("%s",c[i]);
    29         for(i=p*20-1;i>=0;i--)
    30             for(j=i;j>=0;j--){
    31                 if(exist(j,i)) num[j][i]=num[j+1][i]+1;
    32                 else num[j][i]=num[j+1][i];
    33             }
    34         for(i=0;i<p*20;i++) dp[i][1]=num[0][i];
    35         for(i=0;i<p*20;i++)
    36             for(k=2;k<=K;k++)
    37                 for(j=k-1;j<i;j++) dp[i][k]=Max(dp[i][k],dp[j][k-1]+num[j+1][i]);
    38         printf("%d
    ",dp[20*p-1][K]);
    39         return 0;
    40     }
    41 }
    42 int main(){
    43     lys::main();
    44     return 0;
    45 }
  • 相关阅读:
    HDU1266 Reverse Number
    codevs1380 没有上司的舞会
    codevs1163 访问艺术馆
    codevs2144 砝码称重 2
    codevs1553 互斥的数
    codevs1230 元素查找
    codevs3118 高精度练习之除法
    codevs1245 最小的N个和
    codevs1063 合并果子
    codevs1052 地鼠游戏
  • 原文地址:https://www.cnblogs.com/_inx/p/7801173.html
Copyright © 2011-2022 走看看