• 洛谷 P1026 统计单词个数


    题目描述

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

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

    要求输出最大的个数。

    输入输出格式

    输入格式:

     

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

    p表示字串的行数,k表示分为k个部分。

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

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

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

     

    输出格式:

     

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

    输入输出样例

    输入样例#1: 
    1 3
    thisisabookyouareaoh
    4
    is
    a
    ok
    sab
    
    输出样例#1: 
    7
    

    说明

    this/isabookyoua/reaoh

    解题思路:

    本题需先看另一篇博客:https://www.cnblogs.com/lipeiyi520/p/10414227.html

    本题是一个DP题,用一个f数组表示状态,其中f[i][j]表示到了第i个位置,分了j块,能得到的最多的单词数,再枚举断点l,则 dp[i][j]=max{ dp[i][j] , dp[l][j-1]+sum[l+1][i] };sum[i][j]表示i到j的单词数.

    AC代码:

     1 #include<cstdio>
     2 #include<iostream>
     3 using namespace std;
     4 int p,k,n,m,sum[210][210],f[210][50];
     5 string s,a[10];
     6 bool check(int l,int r) {//判断是否有单词以s[l]为开头
     7     string x = s.substr(l,r - l + 1);//取出字符串 
     8     for(int i = 1;i <= n; i++) if(!x.find(a[i])) return true;//查找 
     9     return false;
    10 }
    11 void inin() {//读入+预处理 
    12     string ch;
    13     s += '0';//下标从0开始 
    14     scanf("%d%d",&p,&k);//输入 
    15     for(int i = 1;i <= p; i++) {
    16         cin >> ch;
    17         s += ch;
    18     }
    19     scanf("%d",&n); m = s.length() - 1;//下标从0开始,所以要减一 
    20     for(int i = 1;i <= n; i++) cin >> a[i];//输入单词 
    21     for(int i = m;i >= 1; i--)
    22         for(int j = i;j >= 1; j--) {//预处理sum[i][j] 
    23             sum[j][i] = sum[j+1][i];
    24             if(check(j,i)) sum[j][i]++;
    25         }
    26 }
    27 void dp() {//开始DP 
    28     f[0][0] = 0;
    29     for(int i = 1;i <= k; i++) f[i][i] = f[i-1][i-1] + sum[i][i]; 
    30     for(int i = 1;i <= m; i++) f[i][1] = sum[1][i];//初始化 
    31     for(int i = 1;i <= m; i++) 
    32         for(int j = 1;j <= k && j < i; j++)
    33             for(int l = j;l < i; l++)//设置断点 
    34                 f[i][j] = max(f[i][j],f[l][j-1] + sum[l+1][i]);
    35     printf("%d
    ",f[m][k]);
    36 }
    37 int main()
    38 {
    39     inin();
    40     dp();
    41     return 0;
    42 }

     //NOIP提高 2001 T3

  • 相关阅读:
    Android 使用系统签名打包apk
    创业公司如何巧用工具提高团队生产力——豌豆荚创始人王俊煜讲述团队背后的“利器”
    Spring整合BoneCP+Hibernate配置数据连接池
    EhCache集群方案JGroups
    IOS 目录结构
    关于hibernate的缓存使用
    用webbrowser控件做一个资源管理器,如何得到IE控件中选中(鼠标多选)的文件名称列表?
    轮回!
    转载:谨以此文献给才毕业25年的朋友
    新的开始
  • 原文地址:https://www.cnblogs.com/lipeiyi520/p/10414223.html
Copyright © 2020-2023  润新知