【OJ】速算24点

编写目的

记录一下自己刷OJ题时遇到一个有意思的,不那么复杂的问题:24点问题。

题目描述

速算24点相信绝大多数人都玩过。就是随机给你四张牌,包括 A(1),2,3,4,5,6,7,8,9,10,J(11),Q(12),K(13)。要求只用’+’,’-’,’*’,’/'运算符以及括号改变运算 顺序,使得最终运算结果为24(每个数必须且仅能用一次)。游戏很简单,但遇到无解的情况往往让人很郁闷。你的任务就是针对每一组随机产生的四张牌,判断 是否有解。我们另外规定,整个计算过程中都不能出现小数。

输入

输入数据占一行,给定四张牌。

输出

如果有解则输出"Y",无解则输出"N"。

样例输入

A 2 3 6

样例输出

Y

解决方法

问题分析: 不管怎么运算,最终结果肯定是回答 A [ + - * / ] B == 24 这个问题。这里面的A 和 B不一定是一个数,也可以是一个表达式,比如说 A = (1+5) B = (1+3) ,所以A * B == 24 成立。
所以对于 a b c d 四个数,我们不妨平分成两组,A 和 B两组,然后尝试所有方法,看看能不能凑出这个数。

代码如下:

#include <iostream>

using namespace std;

/**
 * 把 a 和 b 加减乘除 所有可能的结果都写在ary数组中
 * 需要注意 分母为0这种情况
 */
void results(int a,int b,int ary[]) {
    // +
    ary[0] = a+b;

    // -
    ary[1] = a > b ? a-b : b-a;

    // *
    ary[2] = a*b;

    // 如果不能整除的话,放弃这种方案,-999 即表示放弃这种方案
    if(a > b && b!=0 && a%b == 0 ) {
        ary[3] = a/b;
    } else if(b > a && a!=0 && b%a == 0) {
        ary[3] = b/a;
    } else {
        ary[3] = -999;
    }
}

/**
 * 计算出两个数组中数据组合运行的所有可能出现的结果
 * 如果运算结果可以包含24,则返回true,否则返回false
 */
bool judgeOk(int ary1[],int ary2[]) {
    int i,t,j;
    int ary[4];
    for(i=0; i<4; i++) {
        for(t=0; t<4; t++) {
            results(ary1[i],ary2[t],ary);
            for(j=0; j<4; j++) {
                if(ary[j] == 24) {
                    return true;
                }
            }
        }
    }
    return false;
}

/**
 * 把字母与数字一一对应
 */
int toInt(string str) {
    if(str == "A") {
        return 1;
    }

    if(str == "J") {
        return 11;
    }

    if(str == "Q") {
        return 12;
    }

    if(str == "K") {
        return 13;
    }

    if(str == "10") {
        return 10;
    }

    return str[0]-'0';
}

// 欢迎关注 https://blog.csdn.net/smileyan9
int main()
{
    // 输入以及各式转换
    string str1,str2,str3,str4;
    int a,b,c,d;
    cin>>str1>>str2>>str3>>str4;
    a = toInt(str1);
    b = toInt(str2);
    c = toInt(str3);
    d = toInt(str4);

    int ary1[4];
    int ary2[4];

    bool flag = false;
    results(a,b,ary1);
    results(c,d,ary2);
    // 如果(a,b) 与 (c,d)组合就可以凑成24点
    if(judgeOk(ary1,ary2) == true) {
        flag = true;
    } else {
        // 如果不能,则尝试(a,c)与(b,d)组合
        results(a,c,ary1);
        results(b,d,ary2);
        if(judgeOk(ary1,ary2) == true) {
            flag = true;
        } else {
            // 如果不能,则尝试(a,d)与(b,c)组合
            results(a,d,ary1);
            results(b,c,ary2);
            if(judgeOk(ary1,ary2) == true) {
                flag = true;
            }
        }
    }

    if(flag == true) {
        cout<<"Y"<<endl;
    } else {
        cout<<"N"<<endl;
    }

    return 0;
}

总结

因为四个数(或者多个数)的运算最终步骤肯定是转换成两个数的运算,比如1x2x3x4最终就是 6x4,所有题目其实就是研究 24 == A [±*/] B 能不能成功,然后我们把A拆分成两个数的“自由运算”,B也拆分成两个数的“自由运算”,然后就可以凑出结果了。
当然,不一定运算结果是24,也不一定是4个数,这种简单运算最终都是转换成两个数进行运算的。

扩展(不妨思考思考)

问题1:如果答案有解,怎么输出答案的解?
问题2:如果把题目中24改成其他数,怎么解决问题?
问题3:如果不是4个数的运算,而是5个数,或者更多个数的运算,怎么解决问题?

Smileyan
2019年9月15日 21:37

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

smile-yan

感谢您的支持!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值