zoukankan      html  css  js  c++  java
  • 洛谷 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
    
    不得不说最开始我连题意都没看懂,2333。
    大概意思是说,给你一串字符,你将这个字符划分成k块,使每一块包含的单词数总和最多。
    我的想法是用两次动态规划,第一次设置一个数组cnt_word[i][j](不要吐槽为什么名字那么长)
    它表示从i号到j号包含多少单词数,然后就很好推,如果从i号到j号有以i号为头的字母,那么cnt_word[i][j]=cnt_word[i+1][j]+1,
    如果不存在,那么就是cnt_word[i][j]=cnt_word[i+1],
    可以用strstr来判断是否包含,并且判断是否以a[i]开头,
    接下来就很好推了,就是枚举枚举区间。
    注意第一个细节,字符串编号是从0开始,那么,范围应是0-(p*20-1),
    第二,枚举区间时要注意,不要让某个区间为空,那样一定会错(如果没错,不要拆穿我。)
    好了,看不懂的看我代码吧,我会加上注释。
     1 #include <iostream>
     2 #include <fstream>
     3 #include <cstdlib>
     4 #include <cstring>
     5 #include <string>
     6 /* run this program using the console pauser or add your own getch, system("pause") or input loop */
     7 using namespace std;
     8 int cnt_hang=0,cnt_fen=0,cnt_words=0; 
     9 char a[205];
    10 char words[9][205];
    11 int cd_words[9]={0};//记录每个单词的长度 
    12 int cnt_word[205][204]={0};//表示从某开头到某时,能有多少单词.
    13 int jiyi[205][43]={0}; 
    14 void jilv( );
    15 int cha(int ks,int js);
    16 int dg(int ks,int fen);
    17 
    18 
    19 void jilv( ){
    20 for(int y=cnt_hang*20-1;y>=0;y--)//注意范围 
    21 for(int x=y;x>=0;x--){
    22  if(cha(x,y)!=0)cnt_word[x][y]=cnt_word[x+1][y]+1;
    23  else cnt_word[x][y]=cnt_word[x+1][y];    
    24 }
    25 return;      
    26 }
    27 
    28 
    29 int cha(int ks,int js){
    30 for(int x=1;x<=cnt_words;x++){
    31 char *p=strstr(&a[ks],words[x]);
    32 //表示询问单词x是否是从a[ks]到结束这一段的字符的字串.如果不是,会返回0,如果是 就会返回str2在str1中首次出现的地址
    33 if(p!=0&&p-&a[ks]==0&&cd_words[x]<=js-ks+1)return 1;
    34 //如果是字串,且是以a[ks]的字串,并且是在ks到js这一段以内的字串,那么就返回1, 
    35 }    
    36 return 0;        
    37 }
    38 
    39 
    40 int dg(int ks,int fen){
    41 //不要吐槽我为什么不用递推,这下面就很好理解了,就是枚举区间. 
    42 if(fen==1)return cnt_word[ks][cnt_hang*20-1];    
    43 if(jiyi[ks][fen]!=-1)return jiyi[ks][fen]; 
    44 for(int x=ks;x<=cnt_hang*20-fen;x++) 
    45 jiyi[ks][fen]=max(jiyi[ks][fen],dg(x+1,fen-1)+cnt_word[ks][x]);    
    46 return jiyi[ks][fen];    
    47 }
    48 
    49 int main(int argc, char *argv[]) {
    50 cin>>cnt_hang>>cnt_fen;
    51 cin>>a;
    52 for(int x=2;x<=cnt_hang;x++){
    53 char b[205];
    54 cin>>b;
    55 strcat(a,b);//表示将b接在a串后面. 注,大多str开头的函数都必须用<cstring>的头文件 
    56 } 
    57 //cout<<a<<endl; 
    58 cin>>cnt_words;
    59 for(int x=1;x<=cnt_words;x++){
    60  cin>>words[x];    
    61  cd_words[x]=strlen(words[x]);//表示计算长度 
    62 }
    63 jilv( );//第一个动归 
    64 memset(jiyi,-1,sizeof(jiyi));
    65 int ans=dg(0,cnt_fen); //就是一个枚举区间 
    66 cout<<ans; 
    67 return 0;
    68 }

  • 相关阅读:
    C++ primer plus读书笔记——第6章 分支语句和逻辑运算符
    C++ primer plus读书笔记——第7章 函数——C++的编程模块
    C++ primer plus读书笔记——第5章 循环和关系表达式
    C++ primer plus读书笔记——第4章 复合类型
    C++ primer plus读书笔记——第3章 处理数据
    C++ primer plus读书笔记——第2章 开始学习C++
    10款好用到爆的Vim插件,你知道几个?
    程序员最讨厌的100件事,瞬间笑喷了,哈哈~~
    20 个最常用的 Git 命令用法说明及示例
    史上最全的Nginx配置参数中文说明
  • 原文地址:https://www.cnblogs.com/Ateisti/p/5627439.html
Copyright © 2011-2022 走看看