【dfs】【枚举】Tragedy Words CSU - 2087 【摆放元音、辅音字母、L】

【dfs】Tragedy Words CSU - 2087 【摆放元音、辅音字母、L】

As is known to all, Wells doesn’t have a good command of English. As a result, some unfamiliar words, which may cause sadness of Wells, is called tragedy words. In more detail, a word will be defined as a tragedy word, if and only if when it satisfies all following conditions.

First, it only contain uppercase letter.

Second, it doesn’t contain three consecutive vowel(AEIOU) or three consecutive consonant(the other 21 letter).

And last of all, it should contain at least one special tragedy letter ‘L’.

Now, you are given a word, which consists of uppercase letter or underline, and you are allow to fill each underline with one uppercase letter. And in order to make fun of Wells, you want to know how many tragedy words you can make in this way.

Input
For each test, only contains a line of one word, which consists of uppercase letter and underline(’_’).

The total length of each word will not exceed 100, and the number of underline(’_’) will not exceed 10.

Output
For each test, print one line, which contains a integer as the total amount of tragedy words you can make.

Notice: the number may be very large and may exceed the 32-bits unsigned integer.

Sample Input
V__K
V_K

Sample Output
10
0

Hint
The vowel means ‘A’,’E’,’I’,’O’,’U’

The consonant means the other 21 letter.

The special tragedy letter ‘L’ still belongs to consonant.

Of course, the letter here means English letters, not other language letters.

题意:
给一个长度不超过100,最多有10个空格的单词,在空格中填入字母来构造单词使得单词是悲伤单词(不能连续出现三个元音字母或辅音字母、单词须带有字母L、全部为大写字母),问有多少种填法。

思路:
总共就两种字符:元音(AEIOU)、辅音。先预处理字符串,是元音就标记为0, 辅音标记为1,‘_’标记为-10,如果出现了L, 就用flag1标记出来。
因为空格不多,所以直接dfs枚举所有情况,判断是否符合悲伤单词。

  • 枚举:dfs,过程中记录两种字符分别使用了多少次:元音n1, 辅音n2。
  • 判断:从头遍历,如果连续三个相加为0(全为元音),相加为3(全为辅音),则不是悲伤单词。
  • 计算:计算有多少种可能,元音可以填n1次,则有5^n1种填法,辅音可以填n2次,还需要判断原来不填时有没有L,
    • 如果有,那么这n2次,每一次都有21种选择,也就是21^n2种填法。
    • 如果没有,则这n2次中,至少有一次要拿出来填L,由数学组合排列知识知道:至少填一次L = 所有情况(任一填) - 一次都不填L , 即21^n2 - 20^n2
      【开始我写成了21 ^ (n2 - 1),默认只填一次,显然错误了】。

AC代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

const int maxn = 105;
int m[maxn], flag1, flag, len;
char mapp[maxn];
long long ans, n1, n2;

void dfs(int p)
{
    while(p < len && m[p] != -10)
        p++;
    if(p == len)
    {
        flag = 1;
        for(int i = 0; i <= len - 3; i++)
        {
            if(m[i] + m[i + 1] + m[i + 2] == 0 || m[i] + m[i + 1] + m[i + 2] == 3)
            {
                flag = 0;
                break;
            }
        }
        if(!flag)
            return ;
        if(flag1)
            ans += pow(5, n1) * pow(21, n2);
        else
            ans += pow(5, n1) * (pow(21, n2) - pow(20, n2));
        return ;
    }
    m[p] = 1;
    n2++;
    dfs(p + 1);
    n2--;
    m[p] = 0;
    n1++;
    dfs(p + 1);
    n1--;
    m[p] = -10;
}

int main()
{
    while(~scanf("%s", mapp))
    {
        ans = 0;
        flag1 = 0;
        flag = 1;
        n1 = n2 = 0;
        len = strlen(mapp);
        for(int i = 0; i < len; i++)
        {
            if(mapp[i] == 'A' || mapp[i] == 'E' || mapp[i] == 'I' || mapp[i] == 'O' || mapp[i] == 'U')
                m[i] = 0;
            else if(mapp[i] == '_')
                m[i] = -10;
            else
            {
                m[i] = 1;
                if(mapp[i] == 'L')
                    flag1 = 1;
            }
        }
        dfs(0);
        printf("%lld\n", ans);
    }
    return 0;
}

闲话:
看到很多博客都是把字符分为3种情况来写的:元音(5种),辅音除去L(20种),L(1种)。分别在空格中填入这3类字母,可以用A,B,L代替。如果dfs成功(不违反规则并且填完了所有空格),就统计一下填充后的单词,遇到填元音字母的地方就乘5,遇到填辅音字母的地方就乘20。(因为元音字母有5个,辅音字母除去字母L有20个)。

  • 技巧
    数据输入的时候可以开一个数组,存第i个'_'在单词中的位置。便于dfs时找到下一个'_'
for (i = 0; i < Len; i++)
    if (c[i] == '_')
        Que[++Que[0]] = i; //Que[0]是'_'的个数, Que[a]表示第a个'_'的位置

你可能感兴趣的:(dfs,枚举,图论,-,DFS)