[笔试]华为编程大赛题目

1、农场计数问题

/*问题描述
1、已知某农场中有一群鸡和兔子,总共有M个头和N只脚,计算总共有多少鸡和兔子
l 要求实现函数
int GetFowlsNum(int iHeadNum, int iFootNum, int *iChickenNum, int *iRabbitNum)
【输入】    iHeadNum:        总共头的数量
            iFootNum:        总共脚的数量
【输出】    iChickenNum:    鸡的数量
            iRabbitNum:    兔子的数量
【返回】    0:  找到符合要求的鸡和兔子的数量
            -1: 未找到符合要求的数量*/
int GetFowlsNum(int iHeadNum, int iFootNum, int *iChickenNum, int *iRabbitNum){
    if((iFootNum-2*iHeadNum)%2==0){
        int iR=(iFootNum-2*iHeadNum)/2;
        int iC=iHeadNum-iR;
        if(iR>=0 && iC>=0){//当foot=0,head=1时会出现负数。要考虑这种边界情况
            *iRabbitNum=iR;
            *iChickenNum=iHeadNum-iR;
            return 0;
        }
    }
    return -1;
}

 2、字符串压缩

/*问题描述
将给定的字符串,按照规格压缩,输出压缩后的字符串。
压缩规格为:相同字符连续,则压缩为“字符+数字个数”,如”aaaa”压缩为”a4”
注:
1、仅是单个字符连续才压缩,如babababa则不能压缩
2、待压缩字符串中不包含数字和转义符
 要求实现函数
void CompressStr(const char *SrcStr, char *DstStr)
【输入】SrcStr:        待压缩的字符串
【输出】DstStr:        压缩后的字符串
【返回】无*/
void CompressStr(const char *SrcStr, char *DstStr){
    unsigned int count=0;
    while(*SrcStr!='\0'){
        if(*SrcStr==*(SrcStr+1)){
            count++;
        }else if(count>0){
            *DstStr=*SrcStr;
            *(++DstStr)++='0'+count+1;
            count=0;
        }else *DstStr++=*SrcStr;
        SrcStr++;
    }
    *DstStr='\0';//字符串输出最后记得加上\0
}

3、路径查找

/*问题描述
给定N*N字母矩阵,从任意点出发,上,下,左,右移动,在规定方向连续匹配给定的单词序列。
即称为命中,否则不命中,字符矩阵中的字母仅能使用一次,不能在同一单元格停留两次。
字符矩阵最大50*50,都为大写字母。输入1为字母矩阵,输入2为字母序列,输出是否匹配。
int FindStat(const char *Map, unsigned int iArrN, const char *PathStr)
【输入】Map:给定的字母矩阵  iArrN:字母矩阵的行数 PathStr:给定的字母序列
【输出】无
【返回】是否能找到命中的单词序列,命中返回1,否则返回0。*/
int FindStat(const char *Map, unsigned int iArrN, const char *PathStr){
    unsigned int cursor=0;
    unsigned int flag[50];
    memset(flag,0,50*sizeof(unsigned int));
    if(Map[0]==*PathStr){
        flag[0]=1;
        PathStr++;
    }else return 0;
    while(*PathStr!='\0'){
        //向左
        if(cursor%iArrN!=0 && flag[cursor-1]==0 && Map[cursor-1]==*PathStr){
            PathStr++;
            cursor-=1;
            flag[cursor]=1;
            continue;
        //向右 当心负数求模出现不确定结果
        }else if((cursor+1)%iArrN!=0 && flag[cursor+1]==0 && Map[cursor+1]==*PathStr){
            PathStr++;
            cursor+=1;
            flag[cursor]=1;
            continue;
        //向上
        }else if(cursor>=iArrN && flag[cursor-iArrN]==0 && Map[cursor-iArrN]==*PathStr){
            PathStr++;
            cursor-=iArrN;
            flag[cursor]=1;
            continue;
        //向下
        }else if(cursor<iArrN*iArrN-iArrN && flag[cursor+iArrN]==0 && Map[cursor+iArrN]==*PathStr){
            PathStr++;
            cursor+=iArrN;
            flag[cursor]=1;
            continue;
        }else return 0;
    }
    return 1;
}

 2、输入联想

/*问题描述:
输入联想功能是非常实用的一个功能,请编程实现类似功能。
要求实现函数:
void auto_complete(char *str, char *tmp,char *output)
【输入】  char *str,候选字符串
         char *tmp,输入字符串
【输出】  int *output,联想匹配的字符串
【返回】  无
注:候选字符串以空格隔开,输入字符串仅从字符串开始处匹配。
将匹配的子字符串输出,同样以空格隔开。如无匹配成功的子字符串,则输出空字符串。*/
void auto_complete(char *str, char *tmp,char *output){
    vector<char*> words;
    char tok[]=" ";
    char* p=strtok(str,tok);
    while(p){
        words.push_back(p);
        p=strtok(NULL,tok);
    }
    int len=strlen(tmp);
    bool has_match=false;
    for(unsigned int i=0;i<words.size();++i){
        bool flag=true;
        for(int j=0;j<len;++j){
            if(words[i][j]!=tmp[j]){
                flag=false;
                break;
            }
        }
        if(flag){
            char* p=words[i];
            while(*p!='\0') *output++=*p++;
            *output++=' ';
            has_match=true;
        }
    }
    if(words.empty() || !has_match)*output='\0';//如果输入空字符串或没有匹配
    else *--output='\0';//把最后一个空格去掉
}

 1、数组比较

/* 问题描述: 
比较两个数组,要求从数组最后一个元素开始逐个元素向前比较,如果2个数组长度不等,
则只比较较短长度数组个数元素。请编程实现上述比较,并返回比较中发现的不相等元素的个数
比如:数组{1,3,5}和数组{77,21,1,3,5}按题述要求比较,不相等元素个数为0
数组{1,3,5}和数组{77,21,1,3,5,7}按题述要求比较,不相等元素个数为3
要求实现函数: int array_compare(int len1, int array1[], int len2, int array2[])*/
int array_compare(int len1, int array1[], int len2, int array2[]){
    int len=len1<len2?len1:len2;
    int count=0;
    for(int i=len;i>=0;--i){
        if(array1[i]!=array2[i])count++;
    }
    return count;
}

 2、约瑟夫问题

/*问题描述:
输入一个由随机数组成的数列(数列中每个数均是大于0的整数,长度已知),和初始计数值m。
从数列首位置开始计数,计数到m后,将数列该位置数值替换计数值m,并将数列该位置数值出列,
然后从下一位置从新开始计数,直到数列所有数值出列为止。
如果计数到达数列尾段,则返回数列首位置继续计数。
请编程实现上述计数过程,同时输出数值出列的顺
比如: 输入的随机数列为:3,1,2,4,初始计数值m=7,从数列首位置开始计数(数值3所在位置)
第一轮计数出列数字为2,计数值更新m=2,出列后数列为3,1,4,从数值4所在位置从新开始计数
第二轮计数出列数字为3,计数值更新m=3,出列后数列为1,4,从数值1所在位置开始计数
第三轮计数出列数字为1,计数值更新m=1,出列后数列为4,从数值4所在位置开始计数
最后一轮计数出列数字为4,计数过程完成。
输出数值出列顺序为:2,3,1,4。
要求实现函数:
void array_iterate(int len, int input_array[], int m, int output_array[])
【输入】 int len:输入数列的长度;
int intput_array[]:输入的初始数列
int m:初始计数值
【输出】 int output_array[]:输出的数值出列顺序*/
void array_iterate(int len, int input_array[], int m, int output_array[]){
    int count=len,index=0,output_index=0;
    int* flag=new int[len];
    memset(flag,0,len*sizeof(int));
    while(count>0){
        while(m>0){
            if(flag[index]==0) {
                m--;
                if(m==0)break;
            }
            if(index<len-1)index++;
            else index=0;
        }
        output_array[output_index]=input_array[index];
        flag[index]=1;
        m=input_array[index];
        if(index<len-1)index++;
        else index=0;
        count--;
        output_index++;
    }
}
//更简单的方法
void array_iterate_fast(int len, int input_array[], int m, int output_array[]){
    list<int> buf;
    for(int i=0;i<len;++i)buf.push_back(input_array[i]);
    int output_index=0;
    list<int>::iterator iter=buf.begin();
    while(!buf.empty()){
        m--;
        while(m>0){
            iter++;
            if(iter==buf.end())iter=buf.begin();
            m--;
        }
        if(iter==buf.end())break;
        output_array[output_index++]=*iter;
        m=*iter;
        iter=buf.erase(iter);
    }
}

 3、四则运算

/*问题描述:
输入一个只包含个位数字的简单四则运算表达式字符串,计算该表达式的值。
注: 1、表达式只含 +, -, *, / 四则运算符,不含括号 2、表达式数值只包含个位整数(0-9),且不会出现0作为除数的情况 3、要考虑加减乘除按通常四则运算规定的计算优先级 4、除法用整数除法,即仅保留除法运算结果的整数部分。 比如8/3=2。输入表达式保证无0作为除数情况发生 5、输入字符串一定是符合题意合法的表达式,其中只包括数字字符和四则运算符字符, 除此之外不含其它任何字符,不会出现计算溢出情况 要求实现函数: int calculate(int len,char *expStr) 【输入】 int len: 字符串长度; char *expStr: 表达式字符串; 【输出】 无 【返回】 计算结果 思路:当符号栈中还有乘除号时,先把栈顶的加减号出栈,优先计算乘除号。乘除号计算完成以后再计算所有的加减号运算
*/ int calculate(int len,char *expStr){ vector<int> num,numbuf; vector<char> sign,signbuf; int muldiv_num=0; while(*expStr!='\0'){//数字符号分别进栈 if(*expStr=='+' || *expStr=='-'){ sign.push_back(*expStr); } else if(*expStr=='*' || *expStr=='/'){ sign.push_back(*expStr); muldiv_num++; }else{ num.push_back(*expStr-'0'); } expStr++; } while(muldiv_num>0){//如乘除法没处理完,栈顶的符号和数字都暂时出栈,先完成乘除法 if(sign.back()=='+' || sign.back()=='-'){ signbuf.push_back(sign.back()); sign.pop_back(); numbuf.push_back(num.back()); num.pop_back(); }else if(sign.back()=='*'){ int tmp1=num.back(); num.pop_back(); int tmp2=num.back(); num.pop_back(); num.push_back(tmp1*tmp2); muldiv_num--; sign.pop_back(); }else{ int tmp1=num.back(); num.pop_back(); int tmp2=num.back(); num.pop_back(); num.push_back(tmp2/tmp1); muldiv_num--; sign.pop_back(); } } while(!signbuf.empty()){//临时出栈的符号再入栈 sign.push_back(signbuf.back()); signbuf.pop_back(); } while(!numbuf.empty()){//临时出栈的数字再入栈 num.push_back(numbuf.back()); numbuf.pop_back(); } while(!sign.empty()){//处理剩下的加减法 int tmp1=num.back(); num.pop_back(); int tmp2=num.back(); num.pop_back(); if(sign.back()=='+')num.push_back(tmp1+tmp2); if(sign.back()=='-')num.push_back(tmp2-tmp1); sign.pop_back(); } return num.back(); }

 1、逆序

/*问题描述:
将一个字符串中的大写字母顺序颠倒过来,并输出。字符串的长度不超过100个字符。
要求实现函数:
void StringReverse(char* input, char* output)
【输入】input:输入的字符串
【输出】output:输出转换好的逆序字符串
【返回】无*/
void StringReverse(char* input, char* output){
    int len=strlen(input),output_index=0;
    for(int i=len-1;i>=0;--i){
        if(input[i]>='A' && input[i]<='Z'){
            output[output_index]=input[i];
            output_index++;
        }
    }
    output[output_index]='\0';
}

 2、数字膨胀

/*问题描述:
将输入字符串基于如下规则生成新的一字符串,注意,仅处理字符串中的数字:对数字进行膨胀操作:
第一轮膨胀,从第一位开始,从左到右,数字每一位都膨胀为相同的两位数字,
其中已经有连续两位相同的数字不做膨胀操作;
第二轮膨胀,以第一轮膨胀后的字符串为基础,从第一位开始,从左到右,
数字每两位膨胀为相同的四位数字,其中已经有连续四位相同的数字不做膨胀操作。
要求实现函数:
void number_double(char *input, int time, char *output)
【输入】input:输入的字符串
        time:需要进行膨胀的次数
【输出】output:输出结束游戏后的字符串
【返回】无
注:膨胀次数不超过两次*/
void number_double(char *input, int time, char *output){
    int len=strlen(input),o_index=0;
    char buf[5000];
    int* flag=new int[len];
    memset(flag,0,len*sizeof(int));
    for(int i=0;i<len; ){
        if(i==len-1 && input[i]>='0' && input[i]<='9'){
            buf[o_index++]=input[i];
            buf[o_index++]=input[i];
            break;
        }
        if(i+1<len && input[i]>='0' && input[i]<='9' && input[i+1]==input[i]){
            flag[i]=1;
            buf[o_index++]=input[i++];
            buf[o_index++]=input[i++];
        }else if(i+1<len && input[i]>='0' && input[i]<='9' && input[i+1]!=input[i]){
            flag[i]=1;
            buf[o_index++]=input[i];
            buf[o_index++]=input[i++];
        }else buf[o_index++]=input[i++];
    }
    buf[o_index]='\0';
    if(time==1){
        memcpy(output,buf,(strlen(buf)+1)*sizeof(char));
        return;
    }
    o_index=0;
    len=strlen(buf);
    for(int i=0;i<len;){
        if(!(buf[i]>='0' && buf[i]<='9')){
            output[o_index++]=buf[i++];
            continue;
        }
        if(i+3<len && buf[i]==buf[i+1] && buf[i]==buf[i+2] && buf[i]==buf[i+3]){
            for(int j=0;j<4;++j) output[o_index++]=buf[i];
            i+=4;
        }else if(i+1<len && buf[i]==buf[i+1]){
            for(int j=0;j<4;++j) output[o_index++]=buf[i];
            i+=2;
        }else output[o_index++]=buf[i++];
    }
    output[o_index]='\0';
}

 3、通配符字符串替换(*,?不能同时匹配)

/*问题描述:
在一个字符串中查找一个包含通配符的字符子串并将其替换为另外一个子串,请编写函数实现这个功能。
子串中包含的通配符仅有“*”和“?”,“*”可匹配0个或多个任意字符,
“?”能且只能匹配任意一个字符。
要求实现函数:
void replace(char *src, char *subsrc, char *replace, char *result)
【输入】  char *src,源字符串
          char *subsrc,查找子串
          char *replace,替换的子串
【输出】  char *result,替换后的子串
【返回】  无
注:如未找到子串,就将源串直接输出。*/
int find(char* src,char c){
    while(*src!='\0'){
        if(*src==c) return 1;
        else src++;
    }
    return 0;
}
//?情况,返回1代表找到匹配
int match(char* src,char* subsrc){
    int lensrc=strlen(src),lensub=strlen(subsrc);
    if(lensrc<lensub)return 0;
    while(*subsrc!='\0'){
        if(*subsrc!='?' && *subsrc!=*src)return 0;
        else{
            subsrc++;
            src++;
        }
    }
    return 1;
}
//返回从src到最后一个符合的字符的偏移值
int match2(char* src,char* subsrc){
    int result=0;
    while(*subsrc!='\0'){
        char tmp=*subsrc;
        if(*subsrc!='*' && *subsrc!=src[result])return -1;
        else if(*subsrc!='*' && *subsrc==src[result]){
            subsrc++;
            result++;
        }else{//当前是*的情况
            //*后还有字符
            if(*(1+subsrc)!='\0'){
                int i=0,lasti=0;
                char c=*++subsrc;
                while(src[result+i]!='\0'){
                    if(src[result+i]==c)lasti=i;
                    ++i;
                }
                result+=lasti;
            }else{//*在最后情况
                int i=0;
                while(src[result+i]!='\0')i++;
                result+=i;
                subsrc++;
            }
        }
    }
    return --result;
}
void replace(char *src, char *subsrc, char *replace, char *result){
    if(0==find(subsrc,'*')){//*情况
        int i=0,op_index=0;
        while(src[i]!='\0'){
            if(match(src+i,subsrc)){
                char *rp=replace;
                while(*rp!='\0')result[op_index++]=*rp++;
                i+=strlen(subsrc);
            }else result[op_index++]=src[i++];
        }
        result[op_index]='\0';
        return;
    }else{//?情况
        int i=0,op_index=0;
        while(src[i]!='\0'){
            int end=match2(src+i,subsrc);
            if(-1!=end){
                char *p=replace;
                while(*p!='\0')result[op_index++]=*p++;
                i+=end+1;
            }else{
                result[op_index++]=src[i++];
            }
        }
        result[op_index]='\0';
        return;
    }
}

 3、通配符字符串替换(*,?同时匹配)

//返回匹配开始点到结束点的偏移值
int match(char* src,char* subsrc){
    int result=0;
    while(*subsrc!='\0'){
        if(*subsrc!='*' && *subsrc!='?' && *subsrc!=src[result])return -1;//非通配且不等
        else if(*subsrc=='?'){//?情况
            subsrc++;
            result++;
        }else if(*subsrc=='*'){//*情况
            if(*(1+subsrc)!='\0'){//*后还有字符
                int i=0,lasti=0;
                char c=*++subsrc;
                if(c!='?' && c!='*'){//*后是普通字符
                    while(src[result+i]!='\0'){
                        if(src[result+i]==c)lasti=i;
                        ++i;
                    }
                result+=lasti;
                }//*后是特殊字符只需继续执行即可
            }else{//*在最后情况
                int i=0;
                while(src[result+i]!='\0')i++;
                result+=i;
                subsrc++;
            }
        }else if(*subsrc==src[result]){//不是通配符且匹配
            subsrc++;
            result++;
        }else return -1;//理论上上面已经包含所有情况
    }
    return --result;
}
void replace(char *src, char *subsrc, char *replace, char *result){
    int i=0,op_index=0;
    while(src[i]!='\0'){
        int end=match(src+i,subsrc);
        if(-1!=end){//有匹配
            char *p=replace;
            while(*p!='\0')result[op_index++]=*p++;
            i+=end+1;//跳过被匹配部分
        }else{
            result[op_index++]=src[i++];//没匹配部分直接复制
        }
    }
    result[op_index]='\0';//末尾加上结束符
    return;
}

 1、扑克牌比较

/*问题描述:
在扑克中,牌的类型包括:A(1),2,3,4,5,6,7,8,9,T(10),J(11),Q(12),K(13),D(小
鬼devilkin),B(大鬼Belial)。
请做一个简单的程序,输入两张牌的字符,比如"2"和"K",判断牌的大小,规则如下:
B>D>2>A>K>Q>J>10....>3 最小的为3
判断规则:比较cFirstCard和cSecondCard,如果FirstCar大,那么返回1;
如果相同,返回0;如果FirstCar小,返回-1。
要求实现函数:
int CompareOneCard(char cFirstCard, char cSecondCard)
【输入】 char cFirstCard:需要比较的第一张牌
         char cSecondCard: 需要比较的第二张牌
注意:输入的为字符’A’,’2’,…,’9’,’T’,’J’,’Q’,’K’,’D’,’B’
【返回】  int类型:返回两张牌的比较结果
注意:不用考虑输入的合法性,这个由函数的使用者保证。输入的牌均为字符’1’,
’2’…’9’,大写的’A’,’T’,’J’,’Q’,’K’,’D’,’B’。*/
int helper(char card){
    if(card>='3' && card<='9')return int(card-'0');
    if(card=='A')return 14;
    else if(card=='2')return 15;
    else if(card=='T')return 10;
    else if(card=='J')return 11;
    else if(card=='Q')return 12;
    else if(card=='K')return 13;
    else if(card=='D')return 16;
    else return 17;
}
int CompareOneCard(char cFirstCard,char cSecondCard){
    int one=helper(cFirstCard),two=helper(cSecondCard);
    if(one==two)return 0;
    else if(one>two)return 1;
    else return -1;
}

 2、干瞪眼

/*问题描述:
在成都,流行一种扑克游戏叫“干瞪眼”。
使用扑克牌,包括:A(1),2,3,4,5,6,7,8,9,T(10),J(11),Q(12),K(13)。
注意:10用T替换,这里暂时不考虑大鬼和小鬼。
两手牌的大小规则如下:
a) 单牌:4比3大,5比4大,只有两张牌刚好大一点时才能进行比较,比较顺序为:
A>K>Q>J>T>9>8>7>6>5>4>3。
比如:6大于5,但是不能比4大,6和4不能比较。单牌2属于特殊牌,他可以和其他所
有普通单牌比较,并且是最大的。请注意3,他不能大于任何牌。
b) 对子:即两张牌的点数相同,规则和单牌相似,也需要进行类似处理。两个2
是特殊对子,可以大于所有的其他对子。注意:对子和单牌是不能进行比较的。
c) 炸弹:3个点数相同的牌。炸弹可以大于任何单张和对子,炸弹之间的比较不
用像单牌和对子那样,只能大一点才能比较。
只要满足:222>AAA>KKK>QQQ>JJJ>TTT>…>333的规则的即可。即222是最大的,AAA可
以大于KKK,也可以大于333。
d) 其他规则暂不考虑实现
现在请你实现一个程序,自动判断两手牌的大小,注意:输入的牌只会出现3种类型:
单张,对子,炸弹。张数最多3张。不会出现2个单牌。
比如”25”,也不会出现一个对子加单牌,比如”334”等,类似输入异常你可以不用考虑。
但是pFirstCards为单牌,pSecondCards为对子,类似的组合输入是合法的。
要求实现函数:
int CompareCards(char *pFirstCards, char *pSecondCards)
【输入】  char *pFirstCards:需要比较的第一手牌
          char *pSecondCards:需要比较的第二手牌
【返回】  int 类型,返回值说明:
如果pFirstCards和 pSecondCards无法比较,比如”3”和”6”;”55”和”6”等,返回0。
如果pFirstCards大于pSecondCards,返回1。
如果pFirstCards等于 pSecondCards,返回2。
如果pFirstCards小于 pSecondCards,返回3。
注意:不用考虑输入的合法性,这个由函数的使用者保证。
输入的牌均为字符’1’,’2’..’9’,大写的’A’,’T’,’J’,’Q’,’K’。*/
int CompareCards(char *pFirstCards, char *pSecondCards){
    int len1=strlen(pFirstCards),len2=strlen(pSecondCards);
    int result=CompareOneCard(*pFirstCards,*pSecondCards);
    if(len1==3 && len2<3)return 1;//first is bigger
    else if(len2==3 && len1<3)return 3;//second is bigger
    else if(len1==3 && len2==3){
        if(result==1)return 1;
        else if(result==-1)return 3;
        else return 2;
    }else if(len1!=len2)return 0;//can not compare
    else if(len1==len2){//both have one or two card
        if(*pFirstCards=='2' && *pSecondCards!='2')return 1;
        else if(*pFirstCards!='2' && *pSecondCards=='2')return 3;
        else if(*pFirstCards=='2' && *pSecondCards=='2')return 2;
        else if(helper(*pFirstCards)-helper(*pSecondCards)==1)return 1;
        else if(helper(*pSecondCards)-helper(*pFirstCards)==1)return 3;
        else return 0;
    }else return -1;//if this ,error
}

 3、判断麻将吃糊

/*问题描述:
说起麻将,那可是川渝市民的最爱,无论亲朋好友聚会,还是业务谈判,总是少不了麻将的声音。
现实生活如此,网络上各种各样的麻将游戏也非常的多,现在游戏公司H正在做一款麻将游戏,
其中判断是否胡牌的部分希望由你来做。
成都麻将规则如下:
麻将只能包括3种类型:条,筒,万。没有“门、东南西北、红中”。每种牌都是数
字从1到9,每个数字有4张,共36张,筒,万,条均一样。
胡牌规则如下:
a) 手里面的牌最多只有两种类型,即必须打缺一种,不能出现:条,筒,万都存在的情况。
b) 必须有一个对子,即两张相同的牌,比如:两个2筒,两个4条等。
c) 剩余的牌,每3张需要凑成一个有效牌,比如:3个一样的牌(3个2筒),或者3个顺子(1条2条3条),
如果所有的牌都能够凑好,再满足规则b和a,有一个对子,并且所有的牌只有两种,那么就可以胡牌了。
d) 有一种特殊牌,叫做七对,即全部的牌都是成对出现,
比如:2筒2筒5筒5筒3筒3筒4条4条8条8条1条1条2条2条,
一共7对,再满足条件a,也可以胡牌。
e) 假设牌不会出现碰的情况,即手里面的牌肯定是14张。输入数据肯定都是麻将牌,不用考虑异常输入。
也不用考虑会输入“门”,“红中”等成都麻将中不会出现的牌。
要求实现函数:
bool IsMahjonggWin(char *pCards)
【输入】 char *pCards:
参数说明:
假设:
条子为:T,2条输入为:2T
筒子为:D,3筒输入为:3D
万子为:W,4万输入为:4W
pCards:输入麻将序列。比如:”1T2T2T2T3T7T8T9T5D4D7D8D8D8D”
【返回】 bool类型:如果能够胡牌,返回true;如果不能胡牌,返回false。
比如:“7T1T8T2T2T2T3T9T5D4D3D8D8D8D”可以转换成“1T2T3T2T2T 7T8T9T3D4D5D8D8D8D”,可以胡牌。
注意:不用考虑输入的合法性,这个由函数的使用者保证。
输入的牌为字符串,字母为大写的”TDW”,请编码的时候注意。
示例
输入: “1D2D2D2D3D3D4D4D5D5D5D6D6D7D”,返回true
输入: “1D1D1D3D3D3D5D5D5D7D7D7D2W3W”,返回false*/
struct c
{
    int num;
    int count;
};
//有一对以上对子,且只有两种牌
bool isLegal(const vector<int> &cards){
    int couple=0,T=0,D=0,W=0;
    for(unsigned int i=0;i<cards.size();++i){
        if(i<cards.size()-1 && cards[i]==cards[i+1])couple=1;
        if(cards[i]<10)T=1;
        if(cards[i]>10 && cards[i]<20)D=1;
        if(cards[i]>20)W=1;
    }
    if(couple && T+D+W<3)return true;
    else return false;
}
//查找有k张的牌
int find(vector<c> &cards,int k){
    int len=cards.size();
    for(int i=0;i<len;++i){
        if(cards[i].count==k)return i;
    }
    return -1;
}
//判断是否全部牌打完
int isAll(vector<c> &cards){
    int len=cards.size();
    for(int i=0;i<len;++i){
        if(cards[i].count!=0)return 0;
    }
    return 1;
}
//判断是否吃糊
bool IsMahjonggWin(char *pCards){
    //T为1~9,D为11~19,W为21~29
    vector<int> tmp;
    while(*pCards!='\0'){
        if(*(pCards+1)=='T'){
            tmp.push_back(*pCards-'0');
            pCards+=2;
        }else if(*(pCards+1)=='D'){
            tmp.push_back(*pCards-'0'+10);
            pCards+=2;
        }else if(*(pCards+1)=='W'){
            tmp.push_back(*pCards-'0'+20);
            pCards+=2;
        }
    }
    sort(tmp.begin(),tmp.end());
    if(!isLegal(tmp))return false;

    vector<c> cards;
    for(int i=0;i<14;){
        int j=i,n=0;
        while(j<14)if(tmp[i]==tmp[j++])++n;
        c cc;
        cc.count=n;cc.num=tmp[i];
        cards.push_back(cc);
        i+=n;
    }
    int len=cards.size();
    //for(int i=0;i<len;++i)cout<<cards[i].num<<":"<<cards[i].count<<" ";cout<<endl;
    while(find(cards,1)!=-1){//抽取顺子
        int index=find(cards,1);
        if(index<len-2){//顺第一个
            if(cards[index+1].count>0 && cards[index+2].count>0)
                if(cards[index].num+1==cards[index+1].num && cards[index+1].num+1==cards[index+2].num)
                    cards[index].count--;
                    cards[index+1].count--;
                    cards[index+2].count--;
        }else if(index<len-1){//顺第二个
            if(cards[index-1].count>0 && cards[index+1].count>0)
                if(cards[index-1].num+1==cards[index].num && cards[index].num+1==cards[index+1].num)
                    cards[index].count--;
                    cards[index+1].count--;
                    cards[index-1].count--;
        }else if(index<len){//顺第二个
            if(cards[index-2].count>0 && cards[index-1].count>0)
                if(cards[index-2].num+1==cards[index-1].num && cards[index-1].num+1==cards[index].num)
                    cards[index].count--;
                    cards[index-2].count--;
                    cards[index-1].count--;
        }
    }
    //for(int i=0;i<len;++i)cout<<cards[i].num<<":"<<cards[i].count<<" ";cout<<endl;

    while(find(cards,3)!=-1){//抽取碰子
        int index=find(cards,3);
        cards[index].count-=3;
    }
    //for(int i=0;i<len;++i)cout<<cards[i].num<<":"<<cards[i].count<<" ";cout<<endl;

    bool hasTwo=false;
    while(find(cards,2)!=-1){//抽取对子
        hasTwo=true;
        int index=find(cards,2);
        cards[index].count-=2;
    }
    //for(int i=0;i<len;++i)cout<<cards[i].num<<":"<<cards[i].count<<" ";cout<<endl;

    while(find(cards,4)!=-1){//抽取杠子
        int index=find(cards,4);
        cards[index].count-=4;
    }
    //for(int i=0;i<len;++i)cout<<cards[i].num<<":"<<cards[i].count<<" ";cout<<endl;

    return hasTwo && isAll(cards);//有一个以上对子且其他牌全部抽取完毕则可以吃糊
}

 

posted @ 2013-04-13 12:14  iyjhabc  阅读(2508)  评论(0编辑  收藏  举报