谷仓的安保
题目
Farmer John给谷仓安装了一个新的安全系统,并且要给牛群中的每一个奶牛分配一个有效的密码。
一个有效的密码由L(3 <= L <= 15)个小写字母(来自传统的拉丁字母集’a’…‘z’)组成,
至少有一个元音(‘a’, ‘e’, ‘i’, ‘o’, 或 ‘u’)和两个辅音(除去元音以外的音节),
并且是按字母表顺序出现的(例如,'abc’是有效的,而’bac’不是) 。
给定一个期望长度L和C个小写字母,写一个程序,打印出所有的长度为L、能由这给定的C个字母组成的有效密码。
密码 必须按字母表顺序打印出来,一行一个。
你的程序只需输出前25,000个有效密码,即使后面还存在有效密码。
输入
第一行: 两个由空格分开的整数,L和C;
第二行: C个空格分开的小写字母,密码是由这个字母集中的字母来构建的。
输出
第一至N行: 每一个输出行包括一个长度为L个字符的密码(没有空格)。输出
行必须按照字母顺序排列。如果存在多于25,000个有效密码,
你的程序必须在输出25,000个有效密码后停止。
输入样例
4 6
a t c i s w
输出样例
acis
acit
aciw
acst
acsw
actw
aist
aisw
aitw
astw
cist
cisw
citw
istw
题解
题意是从c个字母中选出L个字母组成至少有两个辅音与一个元音的组合,并按序输出。
由于输入不一定有序,而输出要求有序,所以先对输入的字母排序。
然后dfs找出所有组合,最后判断是否符合两辅一元的规定并输出。
代码
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
unsigned long long n,a[1000],b[1000],m,e,c[1000],f,ans=0;
char d[1000];
void dfs(int dep,int j){ //搜索,j用来记录上个字母,本次从j开始搜索就能避免重复
if(dep>n){
if(e>=1&&f>1){
ans++;
for(int i=1;i<=n;i++){
printf("%c",(char)b[i]); //转化为字符输出
}if(ans>=25000){
exit(0);//结束程序
}cout<<endl;
}
}else{
for(int i=j;i<=m;i++){
if(c[i]==0){ //排除出现过的字母
if((char)a[i]=='a'||(char)a[i]=='e'||(char)a[i]=='i'||(char)a[i]=='o'||(char)a[i]=='u'){
e++; //记录元音
}else{
f++; //记录辅音
}
c[i]=1;
b[dep]=a[i];
dfs(dep+1,i);
c[i]=0;
if((char)a[i]=='a'||(char)a[i]=='e'||(char)a[i]=='i'||(char)a[i]=='o'||(char)a[i]=='u'){
e--;
}else{
f--;
}
}
}
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
scanf("%s",&d[i]);
}sort(d+1,d+1+m); //排序
for(int i=1;i<=m;i++){
a[i]=d[i];
}
dfs(1,1);
}