【蓝桥vip试题】ALGO-24 算法训练 统计单词个数
问题描述:
给出一个长度不超过200的由小写英文字母组成的字母串(约定;该字串以每行20个字母的方式输入,且保证每行一定为20个)。要求将此字母串分成k份 (1<k<=40),且每份中包含的单词个数加起来总数最大(每份中包含的单词可以部分重叠。当选用一个单词之后,其第一个字母不能再用。例 如字符串this中可包含this和is,选用this之后就不能包含t)。单词在给出的一个不超过6个单词的字典中。
要求输出最大的个数。
输入格式
第一行有二个正整数(p,k)
p表示字串的行数;
k表示分为k个部分。
接下来的p行,每行均有20个字符。
再接下来有一个正整数s,表示字典中单词个数。(1<=s<=6)
接下来的s行,每行均有一个单词。

1 3 thisisabookyouareaoh 4 is a ok sab
样例输出

7
-----------分界线-----------
这道题算是很基础的字符串模拟题,数据规模只有200,暴力模拟就完事
#对于入门选手,讲一下字符串的比较:
两个字符串相等,就代表了他们对应下标的元素相同。我们需要知道字符串的长度,然后用循环来依次比较。

#include<bits/stdc++.h> using namespace std; int main() { int len_a,len_b,flag; char a[10],b[10]; gets(a); gets(b); len_a=strlen(a); len_b=strlen(b); if(len_a!=len_b)//如果长度不一样,那一定不同 printf("No\n"); else { flag=1;//flag是标记 //这里用len_a或者len_b都可以,因为len_a==len_b for(int i=0;i<len_a;i++) { if(a[i]!=b[i])//如果a和b的对应位置元素出现不同的 { flag=0;//标记变成0,即为不同 break;/跳出循环,后面的就不用比了 } } if(flag==1) printf("Yes\n"); else printf("No\n"); } return 0; }
然后分开讲一下代码思路:
1、输入
题目给的输入比较有意思,是每行20个字符,输入p行。对于字符串的读入可以直接用getchar(),要记得读掉换行符,不然会出错。然后,二维数组不方便换行,所以用了将原来的ch[i][j]换成了ch[i*20+j],这样转换下标就可以把输入数据转换为一维。
输入部分代码:
cin>>p>>k; for(int i=0;i<p;i++) { getchar();//换行符!!! for(int j=0;j<20;j++) ch[i*20+j]=getchar();//正常数据读入 } cin>>s; for(int i=0;i<s;i++) { cin>>d[i];//读入字典 len[i]=strlen(d[i]);//len数组记录字典长度 }
2、判断
判断部分,遍历每一个元素。假设他们都是头,依次进行判断,如果当前字符与字典中的某一串的头相同,则继续进行后续的判断(我用了自定义的check函数)。如果当前的ch[i]可以作为一个头来满足一个单词,则ans++,同时更新end。end是当前满足的单词的最后一个下标,更新他的条件在代码中。当出现同一个头不同词的时候,如果不满足更新end条件,是不会增加ans的。

bool check(int i,int j) { for(int v=1;v<len[j];v++) { if(ch[i+v]!=d[j][v]) return 0; } return 1; }
for(int i=0;i<p*20;i++) { for(int j=0;j<s;j++) { flag=0; if(ch[i]==d[j][0]) { if( check(i,j) ) { if(end<i+len[j]) end=i+len[j]; ans++; flag=1; break; } } if( !flag && k>1 && i>end) k--; }
}
3、后续处理及输出
经过思考,当无效元素足够多的时候,可以随便切并且对答案没有影响。但是会出现一些不够切的情况
比如:
给定字符串为abcabc,字典仅有abc,需要分成k=3段
我们可以看到,如果不考虑分段的话,(abc)(abc)即为最优解,ans=2。但是这样只分了两段,为了满足3段的条件,我们只能去浪费一个单词来满足分段。随便分一下变成了 (abc)(ab)(c),这时满足了k=3的需求,