24点运算

作者: 零岁的我 | 来源:发表于2020-05-21 15:26 被阅读0次

题目描述
计算24点是一种扑克牌益智游戏,随机抽出4张扑克牌,通过加(+),减(-),乘(*), 除(/)四种运算法则计算得到整数24,本问题中,扑克牌通过如下字符或者字符串表示,其中,小写joker表示小王,大写JOKER表示大王:
3 4 5 6 7 8 9 10 J Q K A 2 joker JOKER
本程序要求实现:输入4张牌,输出一个算式,算式的结果为24点。
详细说明:

  1. 运算只考虑加减乘除运算,没有阶乘等特殊运算符号,友情提醒,整数除法要当心;
  2. 牌面210对应的权值为210, J、Q、K、A权值分别为为11、12、13、1;
  3. 输入4张牌为字符串形式,以一个空格隔开,首尾无空格;如果输入的4张牌中包含大小王,则输出字符串“ERROR”,表示无法运算;
  4. 输出的算式格式为4张牌通过+-*/四个运算符相连,中间无空格,4张牌出现顺序任意,只要结果正确;
  5. 输出算式的运算顺序从左至右,不包含括号,如1+2+3*4的结果为24
  6. 如果存在多种算式都能计算得出24,只需输出一种即可,如果无法得出24,则输出“NONE”表示无解。

输入描述: 输入4张牌为字符串形式,以一个空格隔开,首尾无空格;
输出描述: 如果输入的4张牌中包含大小王,则输出字符串“ERROR”,表示无法运算。
因为这里不考虑括号并且只考虑自左向右的运算顺序,所以比较简单。

#include<iostream>
#include<string>
#include<array>
#include<algorithm>
#include<map>

using namespace std;
bool flag = true;

void display(array<float,4> arr)
{
    for(auto value:arr){
        cout<<value<<" ";
    }
    cout<<endl;
}

float compute(float a,float b,int op)
{
    switch(op){
        case 0: return a+b;
        case 1: return a-b;
        case 2: return a*b;
        case 3: 
            if(b==0){
                flag = false;
                return -1;
            }
            else{
                return a/b;
            }
    }
    return 0;
}

string get_op(int op)
{
    switch(op){
        case 0: return "+";
        case 1: return "-";
        case 2: return "*";
        case 3: return "/";
    }
    return " ";
}

string check(array<float,4> arr)
{
    map<int,string> poker={{1,"A"},{2,"2"},{3,"3"},{4,"4"},{5,"5"},{6,"6"},{7,"7"},{8,"8"},{9,"9"},{10,"10"},{11,"J"},{12,"Q"},{13,"K"}};
    int op1,op2,op3;
    string expression="";
    for(int i=0;i<64;++i){
        op1= i%4;
        op2= i/4%4;
        op3=i/16;
        expression = "";
        flag=true; //标志除数是否为0
        //这里只考虑自左向右的顺序计算,并且不考虑符号优先级,如果考虑符号优先级需要使用括号
        if(flag && compute(compute(compute(arr[0],arr[1],op1),arr[2],op2),arr[3],op3)==24 ){
            expression = poker[static_cast<int>(arr[0])] + get_op(op1) + poker[static_cast<int>(arr[1])] + get_op(op2) + poker[static_cast<int>(arr[2])] + get_op(op3) + poker[static_cast<int>(arr[3])];
            return expression;
        }
    }
    return expression;
}

string getPermutation(array<float,4> arr)
{
    sort(arr.begin(),arr.end()); //next_permutation()可以获得基于字典序的全排列,要获得完整的全排列,需要序列初始初始情况下是递增排序的
    string exp = "";
    do{
        exp=check(arr);
        if(exp != "") return exp;
    }while(next_permutation(arr.begin(),arr.end()));
    return exp;
}

int main(int argc,char **argv)
{
    string s=" A234567891JQK"; //可输入合法字符,注意第一个位置是空格,这样可以将其他位置字符对应的数值就是其在字符串中的位置
    bool inputErr=false; //标志是否输入非法字符,即不在s中的字符
    array<float,4> poker;
    for(int i=0;i<4;++i){
        string temp;
        cin>>temp;
        if(temp=="10") poker[i] = stof(temp);
        else if(s.find(temp)!=10 && s.find(temp)!=string::npos){
            poker[i] = s.find(temp);
        }
        else{
            inputErr = true;
        }
    }
    if(inputErr){
        cout<<"ERROR"<<endl;
        return 0;
    }
    string exp=getPermutation(poker);
    if(exp == ""){
        cout<<"NONE"<<endl;
        return 0;
    }
    cout<<exp<<endl;
    return 0 ;
}
运行结果截图

下面是参考别人代码复现的24点游戏,不是对上题的解答。
具体思路请参考:https://blog.csdn.net/octopusflying/article/details/51428337

#include<iostream>
#include<array>
#include<algorithm>
#include<string>
#include<cstring>
#include<map>
using namespace std;

bool flag; //标识运算过程中是否出错,除数是否为0

void display(const array<float,4> arr)
{
    for(auto data:arr){
        cout<<data<<" ";
    }
    cout<<endl;
}

//执行加减乘除运算,包括  反减和反除
float compute(float a,float b,int op)
{
    switch(op){
        case 0:
            return a+b;
            break;
        case 1:
            return a-b;
            break;
        case 2:
            return a*b;
            break;
        case 3:
            if(b==0){
                flag = false;
                return -1;
            }else{
                return a/b;
            }
            break;
        case 4:
            return b-a;
            break;
        case 5:
            if(a==0){
                flag=false;
                return -1;
            }else{
                return b/a;
            }
            break;
    }
}

//以字符形式输出结果等于24的表达式1,这里直接暴力的,可能会有更巧妙的方法?
string getExpression1(array<float,4> const arr,array<int,3> const opArr)
{
    string expression= "((" + to_string(arr[0]);
    for(int i=0;i<3;++i){
        switch(opArr[i]){
            case 0: expression += '+' + to_string(arr[i+1]) ; break;
            case 1: expression += '-' + to_string(arr[i+1]) ; break;
            case 2: expression += '*' + to_string(arr[i+1]) ; break;
            case 3: expression += '/' + to_string(arr[i+1]) ; break;
            case 4: 
                if(i==0) 
                {
                    expression = expression.substr(2);
                    expression = "((" + to_string(arr[i+1]) + '-' + expression ; break;
                }
                if(i==1){
                    expression = expression.substr(1);
                    expression = "(" + to_string(arr[i+1]) + '-' + expression ; break;
                }
                else{
                    expression = to_string(arr[i+1]) + '-' + expression ; break;
                }
            case 5: 
                if(i==0) 
                {
                    expression = expression.substr(2);
                    expression = "((" + to_string(arr[i+1]) + '/' + expression ; break;
                }
                if(i==1){
                    expression = expression.substr(1);
                    expression = "(" + to_string(arr[i+1]) + '/' + expression ; break;
                }
                else{
                    expression = to_string(arr[i+1]) + '/' + expression ; break;
                }
        }
        if(i==0 || i==1) expression += ')';
    }
    // cout<<expression<<endl;
    return expression+"=24";
}

//以字符形式输出结果等于24的表达式2
string getExpression2(array<float,4> const arr,array<int,3> const opArr)
{
    string expression= "";
    bool f=true;
    for(int i=0;i<3;++i){
        switch(opArr[i]){
            case 0: 
                if(i!=1){
                    if(f) expression += '(' + to_string(arr[i]) + '+' + to_string(arr[i+1]) + ')';
                    else expression = '(' + to_string(arr[i]) + '+' + to_string(arr[i+1]) + ')' + expression;
                }
                else{
                    expression += '+';
                }
                break;
            // expression += '+' + to_string(arr[i+1]) ; break;
            case 1: 
                if(i!=1){
                    if(f) expression += '(' + to_string(arr[i]) + '-' + to_string(arr[i+1]) + ')';
                    else expression = '(' + to_string(arr[i]) + '-' + to_string(arr[i+1]) + ')' + expression;
                }
                else{
                    expression += '-';
                }
                break;
            case 2: 
                if(i!=1){
                    if(f) expression += '(' + to_string(arr[i]) + '*' + to_string(arr[i+1]) + ')';
                    else expression = '(' + to_string(arr[i]) + '*' + to_string(arr[i+1]) + ')' + expression;
                }
                else{
                    expression += '*';
                }
                break;
            case 3: 
                if(i!=1){
                    if(f) expression += '(' + to_string(arr[i]) + '/' + to_string(arr[i+1]) + ')';
                    else expression = '(' + to_string(arr[i]) + '/' + to_string(arr[i+1]) + ')' + expression;
                }
                else{
                    expression += '/';
                }
                break;
            case 4: 
                if(i!=1){
                    if(f) expression += '(' + to_string(arr[i+1]) + '-' + to_string(arr[i]) + ')';
                    else expression = '(' + to_string(arr[i+1]) + '-' + to_string(arr[i]) + ')' + expression;
                }
                else{
                    expression = '-' + expression;
                    f = false;
                }
                break;
            case 5: 
                if(i!=1){
                    if(f) expression += '(' + to_string(arr[i+1]) + '/' + to_string(arr[i]) + ')';
                    else expression = '(' + to_string(arr[i+1]) + '/' + to_string(arr[i]) + ')' + expression;
                }
                else{
                    expression = '/' + expression;
                    f=false;
                }
                break;
        }
    }
    return expression+"=24";
}


//判断给定的四个数字是不是可以通过加减乘除运算得到24
void check(array<float,4> arr)
{
    int op_value=0;
    string expression;
    /*因为重新定义了反减和反除两种运算,现在总共有6种运算符,
    算术表达式中需要用到三个运算符,每一个位置的运算符都有6种可能,
    因此共有6^3=216种情况。
    用数字代替运算符:{{0:"+"},{0:"-"},{0:"*"},{0:"/"},{0:"~-"},{0:"~/"},}
    */
    for(op_value=0;op_value<216;++op_value){
        flag=true;
        expression="";
        array<int,3> opArr;
        //得到三个位置运算符的排列
        opArr[0]=op_value%6;
        opArr[1]=op_value/6%6;
        opArr[2]=op_value/36;
        /*定义了反减和反除运算符后,算术表达式中的运算符就都满足交换律了。
        包括使用括号的情况,原本总共7中运算顺序,使用交换律后只有两种运算顺序,
        因为其他运算顺序都可以通过交换律转换为这两种。
        1. 从左到右依次计算:((a ※ b) ※ c) ※ d
        2. 先计算前后两个数字的结果,再计算这两个结果的运算结果:(a ※ b) ※ (c ※ d)

        */
        if(compute(compute(compute(arr[0],arr[1],opArr[0]),arr[2],opArr[1]),arr[3],opArr[2])==24 && flag==true){
            expression = getExpression1(arr,opArr);
            cout<<expression<<endl;
        }
        flag=true;
        expression=""; //计算第二种表达式时记得清空表达式
        if(compute(compute(arr[0],arr[1],opArr[0]),compute(arr[2],arr[3],opArr[2]),opArr[1])==24 && flag==true){
            expression = getExpression2(arr,opArr);
            cout<<expression<<endl;
        }
    }
}

//求序列的全排列
void getPermutation(array<float,4> arr)
{
    sort(arr.begin(),arr.end());
    do{
        // display(arr);
        //判断每一个全排列是不是可以通过运算得到24
        check(arr);
    }while(next_permutation(arr.begin(),arr.end()));
}

int main(int argc,char **argv)
{
    array<float,4> arr;
    string part=" A234567891JKQ";
    bool inputErr=false;
    for(int i=0;i<4;++i){
        string temp;
        cin>>temp;
        if(temp=="10") arr[i] = stof(temp);
        else if(part.find(temp) != string::npos && part.find(temp) !=10){
            arr[i]=part.find(temp);
        }
        else{
            inputErr=true;
        }
    }
    if(inputErr){
        cout<<"ERROR"<<endl;
        return 0;
    }
    // display(arr);
    getPermutation(arr);
    return 0;
}

运行结果复制(图太长):

3 2 4 6
((3.000000-2.000000)*4.000000)*6.000000=24
(3.000000-2.000000)*(4.000000*6.000000)=24
(4.000000/(3.000000-2.000000))*6.000000=24
(4.000000*6.000000)/(3.000000-2.000000)=24
6.000000/((3.000000-2.000000)/4.000000)=24
((3.000000-2.000000)*6.000000)*4.000000=24
(3.000000-2.000000)*(6.000000*4.000000)=24
(6.000000/(3.000000-2.000000))*4.000000=24
(6.000000*4.000000)/(3.000000-2.000000)=24
4.000000/((3.000000-2.000000)/6.000000)=24
((2.000000+4.000000)*3.000000)+6.000000=24
(2.000000+4.000000)+(3.000000*6.000000)=24
(2.000000*4.000000)*(6.000000-3.000000)=24
(2.000000*4.000000)*(6.000000-3.000000)=24
(2.000000+4.000000)+(6.000000*3.000000)=24
((4.000000-2.000000)+6.000000)*3.000000=24
((4.000000/2.000000)+6.000000)*3.000000=24
(6.000000-(2.000000-4.000000))*3.000000=24
(2.000000*6.000000)+(3.000000*4.000000)=24
((6.000000/2.000000)+3.000000)*4.000000=24
(2.000000*6.000000)+(4.000000*3.000000)=24
((6.000000-2.000000)+4.000000)*3.000000=24
((2.000000*6.000000)-4.000000)*3.000000=24
(4.000000-(2.000000-6.000000))*3.000000=24
((3.000000-2.000000)*4.000000)*6.000000=24
(3.000000-2.000000)*(4.000000*6.000000)=24
(4.000000/(3.000000-2.000000))*6.000000=24
(4.000000*6.000000)/(3.000000-2.000000)=24
6.000000/((3.000000-2.000000)/4.000000)=24
((3.000000-2.000000)*6.000000)*4.000000=24
(3.000000-2.000000)*(6.000000*4.000000)=24
(6.000000/(3.000000-2.000000))*4.000000=24
(6.000000*4.000000)/(3.000000-2.000000)=24
4.000000/((3.000000-2.000000)/6.000000)=24
(3.000000*4.000000)+(2.000000*6.000000)=24
(3.000000*4.000000)+(6.000000*2.000000)=24
((3.000000*6.000000)+2.000000)+4.000000=24
(3.000000*6.000000)+(2.000000+4.000000)=24
((6.000000-3.000000)*2.000000)*4.000000=24
(6.000000-3.000000)*(2.000000*4.000000)=24
((3.000000*6.000000)+4.000000)+2.000000=24
(3.000000*6.000000)+(4.000000+2.000000)=24
((6.000000-3.000000)*4.000000)*2.000000=24
(6.000000-3.000000)*(4.000000*2.000000)=24
((4.000000+2.000000)*3.000000)+6.000000=24
(4.000000+2.000000)+(3.000000*6.000000)=24
(4.000000*2.000000)*(6.000000-3.000000)=24
(4.000000*2.000000)*(6.000000-3.000000)=24
(4.000000+2.000000)+(6.000000*3.000000)=24
((4.000000-2.000000)+6.000000)*3.000000=24
((4.000000/2.000000)+6.000000)*3.000000=24
(6.000000-(2.000000-4.000000))*3.000000=24
(4.000000*3.000000)+(2.000000*6.000000)=24
(4.000000*3.000000)+(6.000000*2.000000)=24
((4.000000+6.000000)-2.000000)*3.000000=24
(4.000000*6.000000)*(3.000000-2.000000)=24
(4.000000*6.000000)/(3.000000-2.000000)=24
(4.000000*6.000000)*(3.000000-2.000000)=24
(4.000000*6.000000)/(3.000000-2.000000)=24
(6.000000*2.000000)+(3.000000*4.000000)=24
((6.000000/2.000000)+3.000000)*4.000000=24
((6.000000-2.000000)+4.000000)*3.000000=24
(6.000000*2.000000)+(4.000000*3.000000)=24
((6.000000*2.000000)-4.000000)*3.000000=24
(4.000000-(2.000000-6.000000))*3.000000=24
((6.000000*3.000000)+2.000000)+4.000000=24
(6.000000*3.000000)+(2.000000+4.000000)=24
((6.000000-3.000000)*2.000000)*4.000000=24
(6.000000-3.000000)*(2.000000*4.000000)=24
((6.000000*3.000000)+4.000000)+2.000000=24
(6.000000*3.000000)+(4.000000+2.000000)=24
((6.000000-3.000000)*4.000000)*2.000000=24
(6.000000-3.000000)*(4.000000*2.000000)=24
((6.000000+4.000000)-2.000000)*3.000000=24
(6.000000*4.000000)*(3.000000-2.000000)=24
(6.000000*4.000000)/(3.000000-2.000000)=24
(6.000000*4.000000)*(3.000000-2.000000)=24
(6.000000*4.000000)/(3.000000-2.000000)=24

结果会有重复,但是总的运算量也不大,无所谓。

相关文章

  • 2、Swift 基础运算

    赋值运算 算数运算 余数运算 一元加减法运算 混合赋值运算 比较运算 三元运算 空合运算符 范围运算 逻辑运算

  • Python 入门之常用运算符

    Python中的运算按种类可分为算数运算、比较运算、逻辑运算、赋值运算、成员运算、身份运算、位运算 1、常用运算符...

  • 黑猴子的家:Python 数据运算

    1、算术运算 2、比较运算 3、赋值运算 4、逻辑运算 5、成员运算 6、身份运算 7、位运算 code 8、运算...

  • 运算 & 运算符

    运算 & 运算符 算术运算 比较运算 比较运算的结果为bool值 赋值运算 逻辑运算 位运算 二进制的运算 身份检...

  • 2019-07-23

    R中的基本运算包括:算术运算、关系运算、逻辑运算、赋值运算以及其他运算。 算术运算:四则运算(+,-,*, /),...

  • JS 加、减、乘、除运算避免浮点数

    加法运算 减法运算 乘法运算 除法运算

  • 算术运算符

    算术运算符对数字(文字或变量)执行算术运算。 加法运算 减法运算 乘法运算 除法运算 余数运算 自增自减运算 指数...

  • JavaScript快速入门03-运算符

    JS的运算符 算数运算符 算数运算符用于对数值进行算数运算 运算符描述说明+加法运算-减法运算*乘法运算/除法运算...

  • 技术问 - 运算符有哪些

    算术运算符 赋值运算符 比较运算符 逻辑运算符 位运运算 三目运算符 算术运算符 赋值运算符 比较运算符(关系运算...

  • 逻辑运算,闭包

    算术运算(+-*/%)>比较运算(!==,>= ,<= , = =)>逻辑运算(&&,||)>赋值运算(=)...

网友评论

    本文标题:24点运算

    本文链接:https://www.haomeiwen.com/subject/xfjzohtx.html