目录
题目 牧场安全系统
问题描述:明明是一家养牛场的老板,随着养牛场的规模扩大,牛的数量变得越来越多。因此,管理也就越来越难,还时常发生一些事故,比如:一些牛会走失,一些牛会因为疏忽照顾而生长不佳等等,这些都给明明造成了损失。于是,明明决定给养牛场安装一套现代化的生产管理系统,用科学的方法来管理养牛场,在这套安全系统中,需要为每头牛编一个号码,这个号码是唯一的,用来标识每一头牛。这样明明在管理时,就不会疏忽任意一头牛,也不会使牛再次走失。但是在给每头牛编号的时候,明明遇到了困难,由于系统的原因,系统对每头牛的编号有一定的限制,这个编号必须有L个小写字母组成,这些小写字母必须在固定的几个字母中选择,并且在这个编号中至少要有一个元音(‘a’, ‘e’, ‘i’, ‘o’, 或者 ‘u’),至少有两个辅音(除去元音以外的音节), 并且字母按字母表顺序排列(例如,'abc’是有效的,而’bac’不是有效的)。 例如:假设编号由5个小写字母组成,且这些小写字母只能为a、b、c、d、e、f,这样构成的可能的编号就有以下6种: bcdef acdef abdef abcef abcdf abcde 明明觉得这样编号的方法非常麻烦,仅仅靠手工排列是很难完成的,出错的可能性很大,这时,明明想起了你,你是一位程序设计专家,你能否帮明明写一个程序,帮助他按照编号的规则,由程序生成所有的有效编号,供明明使用。 明明的问题可以归结为:给你一个有效编号的长度L,和C个可用的小写字母,按照编码规则生成所有的有效编号。输入说明:你写的程序要求从标准输入设备中读入测试数据作为你所写程序的输入数据。标准输入设备中有多组测试数据,每组测试数据有二行,第一行为两个整数L(3≤L≤15)和C(3≤C≤26),L表示编号的长度,C表示可以选择的小写字母的数量,L和C用一个空格隔开。第二行有C个两两不相同的小写字母,相互以一个空格隔开。每组测试数据与其后一组测试数据之间没有任何空行,第一组测试数据前面以及最后一组测试数据后面也都没有任何空行。
输出说明:对于每一组测试数据,你写的程序要求计算出一组相应的运算结果,并将这一组运算结果作为你所写程序的输出数据依次写入到标准输出设备中。每组运算结果分为两个部分,第一部分为所有生成的有效编号,每行一个,按字母表逆序顺序输出,第二部分为一个整数,表示总共有多少个有效编码。 每组运算结果的行首和行尾都没有任何空格,每组运算结果与其后一组运算结果之间有一个空行,最后一组运算结果后面没有空行。 注:通常,显示屏为标准输出设备。
输入范例
3 3
a b c
5 6
a b c d e f输出范例
abc
1bcdef
acdef
abdef
abcef
abcdf
abcde
6
题目分析
问题分析:
一开始我想的是把输入的可使用字母组合给分成元音字母和辅音字母两个部分,然后根据元音字母序列分别检测对应元音字母下面有多少种辅音字母序列,并且按照字典序逆序方式分别将这些组合序列输出,但是这种方式涉及到了一元多辅多元多辅等情况,其中元音与辅音字母之间排列与选择太过复杂,导致代码实现未能成功
思路改正:
由于要求长度一定,输出顺序一定(按照字典序逆序方式分别将这些组合序列输出),所以可以将出发点改变,不从他对于至少一个元音两个辅音字母这种要求出发,而是从长度以及输出顺序出发,只是简单对于编号是否合格进行判断,这样可以避免排序*排序问题的复杂。
代码详解与难点分析(可无)
首先便是要把可以选择的全部小写字母排序
int L,C;
while(cin>>L>>C){
char temp;
string library;
while(C--){
cin>>temp;
library+=temp;
}
sort(library.begin(),library.end());
紧接着便是要设计一个函数能够判断编号符不符合下面的要求,该函数为辅助性函数,用于辅助关键函数:solve函数
在这个编号中至少要有一个元音(‘a’, ‘e’, ‘i’, ‘o’, 或者 ‘u’),至少有两个辅音(除去元音以外的音节), 并且字母按字母表顺序排列(例如,'abc’是有效的,而’bac’不是有效的)
该函数分为三部分,一个for循环,两个if语句,分别用来判断元音字母数目,辅音字母数目,以及该string内部字母顺序是否符合题目要求。
bool Qualified(string sernum,int L){
int vonum=0;
bool flag=0;
string tmp=sernum;
for(int i=0;i<5;i++){
if(sernum.find(vowel[i])){//利用了一个元音字母不会出现两次的特性
vonum++;
flag=true;
}
}
if(flag){
flag=false;
if(sernum.size()==L&&sernum.size()-vonum>=2){
flag=true;
}
}
if(flag)
{
flag= false;
sort(sernum.begin(),sernum.end());
if(tmp==sernum)
flag=true;
}
return flag;
}
最后便是关键函数solve函数的设计:
solve函数主要解决编号的生成,以及编号的顺序输出问题。
void solve(string library,int L,int C,int &cot,string &res){
string temp,tmp;
tmp=res;
int num=0;
if(L==C)
{
tmp+=library;
if(Qualified(tmp))
{
cout<<tmp<<endl;
cot++;
}
} else {
for (int i = L; i <= C; i++) {
tmp = res;
if (C - i >= 0 && C - i <= C - 1) {
tmp += library.at(C - i);
temp.assign(library.end() - i + 1, library.end());
solve(temp, L - 1, i - 1, cot, tmp);
} else {
if (Qualified(tmp)) {
cout << tmp << endl;
cot++;
}
i=C;
}
}
}
}
解答
代码
#include "bits/stdc++.h"
using namespace std;
char vowel[10]={'a','e','i','o','u'};
bool Qualified(string sernum){
int vonum=0;
bool flag=0;
string tmp=sernum;
for(int i=0;i<5;i++){
char tmp=vowel[i];
if(sernum.find(tmp)!=sernum.npos){//利用了一个元音字母不会出现两次的特性
vonum++;
flag=true;
}
}
if(flag){
flag=false;
if(sernum.size()-vonum>=2){
flag=true;
}
}
if(flag)
{
flag= false;
sort(sernum.begin(),sernum.end());
if(tmp==sernum)
flag=true;
}
return flag;
}
void solve(string library,int L,int C,int &cot,string &res){
string temp,tmp;
tmp=res;
int num=0;
if(L==C)
{
tmp+=library;
if(Qualified(tmp))
{
cout<<tmp<<endl;
cot++;
}
} else {
for (int i = L; i <= C; i++) {
tmp = res;
if (C - i >= 0 && C - i <= C - 1) {
tmp += library.at(C - i);
temp.assign(library.end() - i + 1, library.end());
solve(temp, L - 1, i - 1, cot, tmp);
} else {
if (Qualified(tmp)) {
cout << tmp << endl;
cot++;
}
i=C;
}
}
}
}
int main(){
int L,C;
while(cin>>L>>C){
char temp;
int cot=0,num=C;
string library,res;
while(num--){
cin>>temp;
library+=temp;
}
sort(library.begin(),library.end());
solve(library,L,C,cot,res);
cout<<cot<<endl;
}
return 0;
}