【蓝桥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,1<k<=40,字典中的单词数不超过6。

 

-----------分界线-----------

这道题算是很基础的字符串模拟题,数据规模只有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;
}
Check

 

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的需求,

posted @ 2022-05-12 10:26  BruceKZ  阅读(88)  评论(0)    收藏  举报