【华为od刷题(C++)】HJ89 24点运算

我的代码:

#include //包含了如排序、排列等常用算法
#include //用于输入输出操作
#include //无序映射,用于将扑克牌的字符映射到对应的数字
#include //动态数组,用于存储输入的扑克牌
using namespace std;

char ops[4] = {
    '+', '-', '*', '/'
};
//这是一个操作符数组,包含了四个基本的数学运算符:加、减、乘、除

unordered_map map_vals = {
    {"2", 2}, {"3", 3}, {"4", 4}, {"5", 5}, {"6", 6}, {"7", 7}, {"8", 8}, {"9", 9}, {"10", 10},
    {"J", 11}, {"Q", 12}, {"K", 13}, {"A", 1}
};
/*map_vals是一个无序映射
作用是将扑克牌的字符值(如"2", "3", "J", "A")转换为对应的整数值
这是为了方便后续的数学计算*/

int cal(int num1, int num2, char op) {
    switch (op) {
        case '+':
            return num1 + num2;
        //如果 op 是加号,返回 num1 与 num2 的和

        case '-':
            return num1 - num2;
        //如果 op 是减号,返回 num1 减去 num2 的结果

        case '*':
            return num1 * num2;
        //如果 op 是乘号,返回 num1 与 num2 的积

        case '/':
            return num1 / num2;
        //如果 op 是除号,返回 num1 除以 num2 的结果
        //这里的除法是整数除法(会舍去余数)
        //如果 num2 是0,程序会崩溃,应该避免除零的情况

        default:
            break;
            //如果 op 不是加、减、乘、除中的任何一个
            //switch 语句将跳过,执行 default 块,什么也不做
    }
    return 0;
}
/*这个函数接受两个整数 num1、num2 和一个字符 op,
根据 op 的值来执行相应的运算并返回结果
运算符包括加法、减法、乘法和除法
如果遇到未知的运算符,返回0*/

int main() {
    vector cards;
    string str;
    while (cin >> str) {
        //这个 while 循环会不断从标准输入读取数据并存储到字符串 str 中
        //直到遇到输入流结束

        if (str == "joker") {
            //如果读取的字符串是 "joker"

            goto go_error;
            //程序会跳转到 go_error 标签处,输出错误信息并退出程序

            //goto 语句用于直接跳转到代码中的指定标签
            //通常不推荐使用 goto
            //因为它会使得程序的控制流程变得难以追踪,增加理解和维护的难度
        }
        cards.emplace_back(std::move(str));
        //如果当前读取的字符串不是 "joker"
        //则通过 emplace_back 将该字符串添加到 cards 向量中

        /*emplace_back 是 C++ 标准库中 std::vector 类的一种成员函数,
        用于在向量的末尾直接构造一个元素
        与 push_back 不同,
        emplace_back 允许直接在容器中构造元素,而无需先创建一个临时对象*/

        //std::move(str) 使得 str 的内容被转移到 cards 中
        //从而避免不必要的复制,提高效率

        /*std::move(str) 是 C++ 标准库中的一个函数,
        它的作用是将对象 str 标记为“可以被移动”的状态,
        从而触发对象的移动语义

        需要注意的是,std::move 本身并不执行任何移动操作,
        它只是告诉编译器这个对象可以被移动了,
        实际的移动操作会在之后的代码中进行*/
    }
    sort(cards.begin(), cards.end());
    //将 cards 向量按字典序排序
    //这个步骤确保了排列顺序的一致性
    //从而为 next_permutation 提供了一个标准的初始排列

    do {
        for (int x = 0; x < 4; ++x) {
            //遍历第一个运算符(x对应ops)

            for (int y = 0; y < 4; ++y) {
                //遍历第二个运算符(y对应ops)

                for (int z = 0; z < 4; ++z) {
                    //遍历第三个运算符(z对应ops)

                    /*ops包含4个基本运算符(+, -, *, /),
                    x, y, 和 z 分别表示不同的位置
                    (第一个、第二个、第三个运算符),
                    每个循环都遍历4个运算符*/

//cal(a, b, op)函数应用指定的运算符(op)对a和b进行计算,并返回结果
                    int num = cal(map_vals[cards[0]], map_vals[cards[1]], ops[x]);
                    /*使用 cards[0] 和 cards[1] 对应的数值进行计算,
                    操作符为 ops[x]
                    计算结果存储在 num 中

                    map_vals[cards[0]]:
                    map_vals 是一个映射或数组,
                    其中存储了每个卡片的数值

                    cards 是一个存储卡片索引的数组,
                    cards[0] 是第一个卡片的索引

                    map_vals[cards[0]] 获取对应卡片的数值

                    ops 是一个包含操作符(如 +, -, *, /)的数组,
                    x 是当前运算符在 ops 数组中的索引
                    ops[x] 就是当前运算符,用于对数字进行运算*/

                    num = cal(num, map_vals[cards[2]], ops[y]);
                    /*上一步的结果 num 再与 cards[2] 对应的数值进行计算,
                    操作符为 ops[y]
                    计算结果更新 num*/

                    num = cal(num, map_vals[cards[3]], ops[z]);
                    /*上一步的结果 num 再与 cards[3] 对应的数值进行计算,
                    操作符为 ops[z]
                    计算结果更新 num*/

                    //num 最终存储的是一个通过四个数字和三个运算符计算后的结果

                    if (num == 24) {
                        //判断当前运算结果 num 是否为 24
                        //如果是,说明已经找到一个合法的表达式

                        str = cards[0] + ops[x] + cards[1] + ops[y] + cards[2] + ops[z] + cards[3];
                        //如果找到了正确的结果
                        //将卡片数字和运算符组合成一个表达式字符串 str

                        goto go_find;
                        //如果找到了结果,跳转到 go_find 标签处
                        //输出最终的表达式
                    }
                }
            }
        }
    } while (next_permutation(cards.begin(), cards.end()));
    //使用 next_permutation 对卡片数组 cards 进行全排列
    //尝试所有的数字排列组合,确保没有遗漏任何可能的顺序

    /*next_permutation 是 C++ STL(标准模板库)中的一个函数,
    属于  头文件
    它用于生成输入序列的下一个字典序排列

    参数:
    first 和 last:
    指向容器(如数组、vector 等)开始和结束位置的迭代器
    这个范围内的元素将进行排列

    返回值:
    如果容器已经是最后一个排列,
    next_permutation 返回 false,
    并且容器元素顺序不会改变

    如果容器不是最后一个排列,
    它会将容器调整为字典序中的下一个排列,
    并返回 true

    next_permutation 的工作原理:
    字典序排列:next_permutation 会返回给定序列的下一个排列,
    如果当前序列已经是字典序中的最后一个排列,它会返回 false,
    表示无法生成下一个排列

    如何生成下一个排列:
    从序列的右端开始,找到一个“下降点”,即找到一个元素,它比右侧的元素小
    接着,在右侧元素中找到一个比该元素大的最小元素,交换这两个元素
    最后,将右侧的元素按升序排列*/

    cout << "NONE";
    //如果所有排列组合都没有找到符合条件的解(即没有 num == 24 的情况)
    //则输出 "NONE"

    return 0;

go_find:
//这是一个标签,用于跳转到找到解后输出表达式的部分

    cout << str;
    //输出找到的表达式 str,即满足 num == 24 的计算式
    return 0;

go_error:
//如果代码中出现错误,会跳转到这个标签并输出 "ERROR"

    cout << "ERROR";
    //输出 "ERROR" 表示程序在执行过程中遇到错误

    return 0;
    //程序结束时返回 0,表示正常结束
}

这段代码是一个用于解决扑克牌计算游戏的程序,目标是通过一组扑克牌中的数字和运算符,计算出等于 24 的表达式;以下是该代码的主要思路总结:

  1. 包含的头文件

    • #include :提供排序和排列等常用算法
    • #include :用于输入输出操作
    • #include :无序映射,将扑克牌的字符映射到对应的数字
    • #include :动态数组,用于存储输入的扑克牌
  2. 运算符数组:定义了一个包含四个基本运算符(加、减、乘、除)的字符数组 ops,供后续计算使用

  3. 映射扑克牌的字符值: 使用 unordered_map 将扑克牌的字符值(如 "2", "3", "J", "A")映射为对应的数字(如 "2" -> 2,"A" -> 1,"J" -> 11,"Q" -> 12,"K" -> 13)

  4. 运算函数 cal: 定义了一个 cal 函数,用于执行给定两个数字和一个运算符的数学运算;支持加、减、乘、除操作;除法是整数除法,舍去余数

  5. 主函数实现

    • 通过循环输入扑克牌的字符并存储在 cards 向量中,直到遇到输入流结束
    • 对输入的扑克牌进行排序,以便后续的排列计算
    • 使用 next_permutation 生成扑克牌的所有排列组合,确保所有可能的顺序都被尝试
    • 在每一种排列下,尝试用不同的运算符组合计算结果
    • 如果找到符合条件的计算式(结果为 24),则输出该表达式
    • 如果所有排列都无法得到结果,输出 "NONE"
  6. 异常处理

    • 如果输入中包含 "joker",程序会跳转到 go_error 标签,输出 "ERROR"
    • 在找到有效解时,程序跳转到 go_find 标签,输出正确的表达式
  7. 使用 goto 语句

    代码中使用 goto 语句跳转到不同的标签来处理错误或输出解,这种做法不推荐,但在这段代码中用于简化控制流

代码中的关键步骤:

  • 输入处理:读取扑克牌并存入 cards 向量
  • 排列计算:利用 next_permutation 来遍历扑克牌的所有排列,并通过运算符组合计算
  • 结果判断:若某个排列和运算符组合的结果为 24,输出结果;否则输出 "NONE"

总结:

该程序通过穷举法,尝试所有可能的扑克牌排列和运算符组合,找出可以通过加、减、乘、除得到 24 的表达式;如果没有找到,输出 "NONE"

你可能感兴趣的:(华为od,c++,开发语言)