题解 | #24点游戏算法#

24点游戏算法

http://www.nowcoder.com/practice/fbc417f314f745b1978fc751a54ac8cb

题目的主要信息:

给出4个1-10的数字,通过加减乘除运算,得到数字为24就算胜利,除法指实数除法运算,本题对数字选取顺序无要求,但每个数字仅允许使用一次,且不考虑括号运算。

方法一:

首先将给定的四个数字提取出来,然后对四个数字的所有排列枚举一遍,每个排列都判断是否能完成24点计算,如果能,则结束循环,输出运算。判断是否能完成24点也是用暴力枚举的方式,首先枚举第一个运算符,然后再枚举第二个运算符,枚举第三个运算符,如果当前运算符的选择可以的到结果24则结束递归。 alt 具体做法:

#include <bits/stdc++.h>
using namespace std;

bool get(double a, double b, char& op1) {//穷举最后一个符号
    if (a + b == 24) {
        op1 = '+';
        return true; 
    }
    if (a - b == 24) { 
        op1 = '-'; 
        return true; 
    }
    if (a * b == 24) {
        op1 = '*'; 
        return true; 
    }
    if (a / b == 24) { 
        op1 = '/'; 
        return true; 
    }
    return false;
}

bool get(double a, double b, double c, char& op1, char& op2) {//穷举第二个运算符
    if (get(a + b, c, op2)) {
        op1 = '+';
        return true; 
    }
    if (get(a - b, c, op2)) {
        op1 = '-'; 
        return true; 
    }
    if (get(a * b, c, op2)) { 
        op1 = '*';
        return true;
    }
    if (get(a / b, c, op2)) { 
        op1 = '/'; 
        return true;
    }
    return false;
}

bool get(double a, double b, double c, double d, char& op1, char& op2, char& op3) {//穷举第一个符号
    //+ - * /每一种方法都穷举一遍,递归计算
    if (get(a + b, c, d, op2, op3)) { 
        op1 = '+'; 
        return true; 
    }
    if (get(a - b, c, d, op2, op3)) { 
        op1 = '-'; 
        return true; 
    }
    if (get(a * b, c, d, op2, op3)) { 
        op1 = '*'; 
        return true; 
    }
    if (get(a / b, c, d, op2, op3)) { 
        op1 = '/';
        return true;
    }
    return false;
}

int main() {
    vector<double> num(4, 0);
    while (cin >> num[0] >> num[1] >> num[2] >> num[3]) {
        sort(num.begin(), num.end());
        bool flag = false;
        char op[3];
        do {
            if (get(num[0], num[1], num[2], num[3], op[0], op[1], op[2])) {//如果这个排列可以完成24点运算
                cout << "true" << endl;
                flag = true;//找了一种解法,flag为true
                break;
            }
        } while (next_permutation(num.begin(), num.end()));//每个排列都遍历一遍
        if (!flag){
            //没有找到解法
            cout << "false" << endl;
        }
    }


}


复杂度分析:

  • 时间复杂度:O(1)O(1),虽然过程繁琐,但是说到底是对4个数的运算进行枚举,只需要常数时间。
  • 空间复杂度:O(1)O(1),因为是对4个数进行运算,递归栈的大小是常数。

方法二:

方法一中我们枚举了所有操作数可能的顺序,同样的,我们也可以对运算符进行枚举。最终我们只需在三个地方用到运算符,每个地方运算符都可能是+/+−∗/中的一种,总共有4x4x4种可能,我们枚举所有操作数的顺序和运算符的64种可能,计算当前操作数顺序和运算符顺序下的结果,如果结果为24,则结束枚举,输出运算过程。运算符的64种顺序枚举用三个for循环实现,calculator函数计算当前操作数顺序和运算符的结果。

具体做法:

#include <bits/stdc++.h>
using namespace std;

vector<char> op={'+', '-', '*', '/'};
vector<char> operation;//当前的运算符顺序


double calculator(vector<int> num, vector<char> operation) {//计算当前顺序的操作数和运算符的结果
    double sum=num[0];
    for(int i=0,j=1;i<operation.size();i++,j++){
        switch(operation[i]){
            case '+':
                sum += num[j];
                break;
            case '-':
                sum -= num[j];
                break;
            case '*':
                sum *= num[j];
                break;
            case '/':
                sum /= num[j];
                break;
        }
    }
    return sum;
}

bool dfs(int a, int b, int c, int d) {
    vector<int> num = {a, b, c, d};
    for(int i=0;i<op.size();i++){//三个循环枚举所有的操作符顺序可能
        for(int j=0;j<op.size();j++){
            for(int k=0;k<op.size();k++){
                operation = {op[i], op[j], op[k]};//枚举所有可能的运算符顺序
                double sum = calculator(num, operation);//计算结果
                if(sum == 24.0){//若结果为24则结束枚举
                    return true;
                }
            }
        }
    }
    return false;
}

int main() {
    vector<int> num(4,0);
    while (cin >> num[0] >> num[1] >> num[2] >> num[3]){
        sort(num.begin(), num.end());
        bool flag = false;
        char op[3];
        do {
            if (dfs(num[0], num[1], num[2], num[3])) {//如果这个操作数排列可以完成24点运算
                cout << "true" << endl;
                flag = true;
                break;
            }
        } while (next_permutation(num.begin(), num.end()));//每个排列都遍历一遍
        if (!flag){
            //没有找到解法
            cout << "false" << endl;
        }
    }


}



复杂度分析:

  • 时间复杂度:O(1)O(1),虽然有三个for循环,但是总共只有64种可能,只需要常数时间。
  • 空间复杂度:O(1)O(1),只用了常数空间。
全部评论

相关推荐

喜欢吃蛋糕仰泳鲈鱼是我的神:字节可以找个hr 给你挂了,再放池子捞
点赞 评论 收藏
分享
牛客963010790号:为什么还要收藏
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务