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'不是)。
谷仓的安保
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
输入格式:
* 第一行: 两个由空格分开的整数,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
acis
acit
aciw
acst
acsw
actw
aist
aisw
aitw
astw
cist
cisw
citw
cstw
istw
解答:
这道题的解法和求一个集合的幂集很相似,都是通过对一棵深度为n+1(n为集合的元素个数,在本题中,n为小写字母的个数)的满二叉树进行深度优先遍历,在每次访问孩子节点时,向左表示对该层所表示的字母做取操作,向右表示对该层所表示的字母做舍操作.根节点是第一层,是起始状态.从第二层开始依次表示字母集合的第一个字母,第二个字母...,这样,n+1层刚好表示了n个字母.每当遍历到满二叉树的叶子节点时,我们也就得到了一个字母取舍序列,在这个序列中,有的字母被取到,有的字母没被取到,所有这样的序列就组成了先前n个字母组成的集合的一个幂集.本题中要求的密码集合其实是小写字母集合的幂集的子集,所不同的是它们的长度被做了限制,同时要求至少包含一个元音和两个辅音,我们只要先求出幂集,在根据条件过滤掉不符合要求的幂集元素,剩下的就是我们要求的密码了.
关于求解幂集的思想和方法,在我的blog中有一篇文章讲到,地址如下:
关于求解幂集的思想和方法,在我的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 }
- C /C++编程挑战题:谷仓的安保解法[二叉树的运用]
- c的二叉树
- 编程算法 - 二叉树的深度 代码(C)
- 编程算法 - 二叉树的最低公共祖先 代码(C)
- C版本的二叉树
- c语言-if的运用
- C++builder 消息的运用
- java二叉树的运用
- 二叉树的基本操作及编程题总结(C++)
- 用c语言编程实现二叉树的建立和遍历二叉树
- 关于约瑟夫环的c语言解法
- 约瑟夫环问题(Josephus)的C解法
- C语言求素数的不同解法
- 数独的解法c语言
- Lu分解法的C语言实现
- POJ 1426 二叉树的解法
- 《编程之美: 求二叉树中节点的最大距离》的另一个解法
- 《编程之美: 求二叉树中节点的最大距离》的另一个解法
- javaScript中关于动态添加select选项的操作。。。。。。
- minix3的适用范围
- c++回忆1—《C++大学教程》
- Minix引导过程分析
- 2个工具
- C /C++编程挑战题:谷仓的安保解法[二叉树的运用]
- 幕后英雄的用武之地——浅谈Java内部类的四个应用场景
- 西行漫记(5):关于故事的故事
- 开始比较深入的接触 javascript 。(draft version)
- 等待
- volatile(读书笔记)
- 关于如何在java的web应用获取服务器资源。
- 猴子搬香蕉
- IO操作的时候,不要忽视flush