C /C++编程挑战题:谷仓的安保解法[二叉树的运用]

来源:互联网 发布:随机梯度下降算法参数 编辑:程序博客网 时间:2024/06/09 20:20
C /C++编程挑战题:谷仓的安保解法

作者:yxin1322
 blog:http://blog.csdn.net/yxin1322  转载请注明出处

题目:
谷仓的安保
Farmer John给谷仓安装了一个新的安全系统,并且要给牛群中的每一个奶牛安排一个有效的密码。一个有效的密码由L(3 <= L <= 15)个小写字母(来自传统的拉丁字母集'a'...'z')组成,至少有一个元音('a', 'e', 'i', 'o', 或者 'u'),至少两个辅音(除去元音以外的音节),并且按字母表顺序出现(例如,'acd'是有效的,而'dac'不是)。
给定一个期望长度L和C个小写字母,写一个程序,打印出所有的长度为L、能由这些字母组成的有效密码。密码必须按字母表顺序打印出来,一行一个。
题目名称: passwd
输入格式:
* 第一行: 两个由空格分开的整数,L和C
* 第二行: C个空格分开的小写字母,密码是由这个字母集中的字母来构建的。
输入样例 (文件 passwd.in):
4 6
a t c i s w
输入详细说明:
由从给定的六个字母中选择的、长度为4的密码。
输出格式:
* 第一至?行: 每一个输出行包括一个长度为L个字符的密码(没有空格)。输出行必须按照字母顺序排列。
输出样例 (文件 passwd.out):
acis
acit
aciw
acst
acsw
actw
aist
aisw
aitw
astw
cist
cisw
citw
cstw
istw

解答:
  这道题的解法和求一个集合的幂集很相似,都是通过对一棵深度为n+1(n为集合的元素个数,在本题中,n为小写字母的个数)的满二叉树进行深度优先遍历,在每次访问孩子节点时,向左表示对该层所表示的字母做取操作,向右表示对该层所表示的字母做舍操作.根节点是第一层,是起始状态.从第二层开始依次表示字母集合的第一个字母,第二个字母...,这样,n+1层刚好表示了n个字母.每当遍历到满二叉树的叶子节点时,我们也就得到了一个字母取舍序列,在这个序列中,有的字母被取到,有的字母没被取到,所有这样的序列就组成了先前n个字母组成的集合的一个幂集.本题中要求的密码集合其实是小写字母集合的幂集的子集,所不同的是它们的长度被做了限制,同时要求至少包含一个元音和两个辅音,我们只要先求出幂集,在根据条件过滤掉不符合要求的幂集元素,剩下的就是我们要求的密码了.
  关于求解幂集的思想和方法,在我的blog中有一篇文章讲到,地址如下:

  http://blog.csdn.net/yxin1322/archive/2006/01/08/573987.aspx

  我写的求解密码的代码如下:为了简化操作,我没有从文件中读取数据,而是直接从控制台输入.并且仅需要输入小写字母集合(小写字母之间不需要空格)和密码长度,题目要求输入的小写字母个数在程序中能够自己计算得出,故不需要输入.还需要说明的是,本程序仅仅是为了验证求解密码集合的算法,为了尽量简洁,对用户的输入没有进行合法性检查,所以大家尽可以在要输入数字的地方输入字母,在要输入小写字母的地方输入大写字母,程序都不会提示非法,只是执行起来后果就不得而知了^_^.
1    /*2    Code by : yxin13223    http://blog.csdn.net/yxin13224    Email: yxin1322@163.com5    Date: 2005.1.146    */7    8    #include <stdio.h>9    #include <string.h>10    11    #define MAX_LENGTH 27 /*字符数:26小写字母+'/0'      */12    13    void MakePassWord(char*, int, int, char*, int, int, int*);/*用于构造密码的递归函数*/14    void SortCharacterSet(char *); /*对输入的字符集进行排序*/15    16    int main()17    {18    char CharacterSet[MAX_LENGTH];/*存放输入的小写字母集*/19    char Password[MAX_LENGTH]="/0";/*存放生成的password*/20    int NumOfPassword=0;/*存放生成的password数量*/21    int PassLen;/*存放指定的密码长度*/22    23    printf("Input the character set/n");/*输入小写字母集合,字母之间无空格*/24    printf("[ all the characters are different from each other ]/n");25    printf("[ And all the characters must be a lowercase ]/n");26    printf("Now Input:");27    scanf("%s",CharacterSet);28    29    SortCharacterSet(CharacterSet); /*为了让密码按字母顺序打出,需要对字符集排序*/30    //printf("After sort: %s",CharacterSet);31    32    printf("/nInput the length of the password:");/*输入指定的密码长度*/33    scanf("%d",&PassLen);34    35    MakePassWord(CharacterSet,0,PassLen,Password,0,0,&NumOfPassword);/*调用递归函数*/36    printf("/n");37    printf("Number of Passwords: %d/n",NumOfPassword);38    }39    40    /*41    构造密码的递归函数42    参数说明:char* character_set: 小写字符集43    int i: 当前取舍第i个小写字符44    int pass_len: 指定的密码长度45    char* password: 当前已经生成的部分密码46    int NumOfConsonant: 当前生成的部分密码中,辅音字母的个数47    int NumOfVowel: 当前生成的部分密码中,元音字母的个数48    int* NumOfPass: 当前已经生成的合法的密码个数49    */50    void MakePassWord(char* character_set, int i, int pass_len,char* password, 51      int NumOfConsonant, int NumOfVowel, int * NumOfPass)52    {53    char TempPass[MAX_LENGTH];54    strcpy(TempPass,password);  /*为当前已经生成的部分密码生成副本*/55    56    /*如果所有小写字母都已经在生成密码中进行了取舍,则检验是否是符合要求的密码*/57    if(i>=strlen(character_set))58    {59    /*如果当前生成的密码中元音和辅音个数以及密码长度都符合要求,则打印该密码*/60    if((NumOfConsonant>=2 && NumOfVowel>=1) && strlen(TempPass)==pass_len)61    {62    printf("password[%4d]:  %s/n",*NumOfPass+1,TempPass);63    (*NumOfPass)++;64    }65    }66    else/*若还有小写字母没有经过取舍,则继续取舍的递归操作*/67    {68    69    /*更新统计当前生成的部分密码中元音和辅音的个数*/70    if((((character_set[i]=='a' || character_set[i]=='e') || character_set[i]=='i')71    || character_set[i]=='o') || character_set[i]=='u')72    {73    NumOfVowel++;74    }75    else76    {77    NumOfConsonant++;78    }79    80    /*将第i个字母进行取舍,分为取和舍两中情况*/81    strncat(TempPass,(character_set+i),1); 82    83    /*取字母i为密码的一部分,进入递归调用*/84    MakePassWord(character_set,i+1,pass_len,TempPass,85    NumOfConsonant,NumOfVowel,NumOfPass);86    87    /*不取i为密码的一部分,进入递归调用*/88    MakePassWord(character_set,i+1,pass_len,password,89    NumOfConsonant,NumOfVowel,NumOfPass);90    }91    }92    93    94    /*用冒泡法对给定字符集进行排序*/95    void SortCharacterSet(char * set)96    {97    int i;98    int j;99    char temp;100    101    for(i=strlen(set)-1;i>=1;i--)102    {103    for(j=0;j<=i-1;j++)104    {105    if(set[j]>set[j+1])106    {107    temp=set[j];108    set[j]=set[j+1];109    set[j+1]=temp;110    }111    }112    }113    }
原创粉丝点击