• CCF-201903-2-二十四点


    CCF-201903-2-二十四点

    CCF题目

    样例1

    样例2

    成功案例

    主函数

    1. //输入数据的主函数
    2. int main() {
    3.     int n;
    4.     cin >> n;
    5.     string str[100];
    6.     for (int i = 0; i < n; i++) {
    7.         char s[6];
    8.         cin >> s;
    9.         str[i] = s;
    10.     }
    11.     for (int i = 0; i < n; i++) {
    12.         int ans = jisuan(str[i]);
    13.         if (ans == 24) {
    14.             cout << "Yes" << endl;
    15.         } else {
    16.             cout << "No" << endl;
    17.         }
    18.     }
    19.     return 0;
    20. }

    计算方法

    了解了前缀表达式,中缀表达式,后缀表达式的相关定义后,就明白了。

    核心计算方法是把减号换成负数相加,对乘号和除法直接计算结果,最后累和得到结果!

    数据结构上使用了,理论是是逆波兰式,对后缀表达式进行的遍历操作。

    有人说逆波兰式和波兰式是有区别的,但是核心都是扫描到两个数值与一个运算符进行运算,结果压栈继续反复。

    请原谅我区分不出来两者的区别。

    1. //计算字符串str对应的结果
    2. int jisuan(string str) {
    3.     stack<int> sint;
    4.     for (int i = 0; i < 7; i++) {
    5.         if (str[i] == '+') {
    6.         } else if (str[i] == '-') {
    7.             sint.push('0' - str[i + 1]);
    8.             i = i + 1;
    9.             continue;
    10.         } else if (str[i] == 'x') {
    11.             int t = sint.top() * (str[i + 1] - '0');
    12.             sint.pop();
    13.             sint.push(t);
    14.             i = i + 1;
    15.             continue;
    16.         } else if (str[i] == '/') {
    17.             int t = sint.top() / (str[i + 1] - '0');
    18.             sint.pop();
    19.             sint.push(t);
    20.             i = i + 1;
    21.             continue;
    22.         } else {
    23.             sint.push(str[i] - '0');
    24.         }
    25.     }
    26.     int sum = 0;
    27.     while (sint.size() > 0) {
    28.         sum += sint.top();
    29.         sint.pop();
    30.     }
    31.     return sum;
    32. }

    失败过程

    思路一(失败)

    主函数

    先简单的把主函数写出来,还是从txt文档里输入数据,用数组保存信息之后,建立对应的函数,完成第一步操作。

    1. #include<iostream>
    2. #include <fstream>
    3. #include<string>
    4. #include <stack>
    5. using namespace std;
    6. int main() {
    7.     ifstream fin("1.txt");
    8.     if (!fin) {
    9.         return -1;
    10.     }
    11.     int n;//一共多少组算式
    12.     fin >> n;
    13.     string *str = new string[n];
    14.     for (int i = 0; i < n; i++) {
    15.         fin >> str[i];
    16.     }
    17.     for (int i = 0; i < n; i++) {
    18.         cout << judge_4(str[i]) << endl;
    19.     }
    20.     fin.close();
    21.     return 0;
    22. }

    计算函数体

    建立judge_4函数体。

    1. string judge_4(string s) {
    2.     stringstream ss;//方便类型转换
    3.     double a, b, c, d;//四个数值
    4.     char ch;//临时记录
    5.     string temp = "";//临时记录
    6.     string str = "";//进行一次计算后,还保留了三个数值和两个运算符
    7.     ch = s[0] - '0';
    8.     a = ch;
    9.     ch = s[2] - '0';
    10.     b = ch;
    11.     ch = s[4] - '0';
    12.     c = ch;
    13.     ch = s[6] - '0';
    14.     d = ch;
    15.     if (s[1== 'x' || s[1== '/') {
    16.         if (s[1== 'x') {//进行运算
    17.             a = a * b;
    18.         } else {
    19.             a = a / b;
    20.         }
    21.         ss << a;//类型转换
    22.         temp = ss.str(); //完成类型转换
    23.         str += temp;
    24.         str += s.substr(3);
    25.     } else if (s[3== 'x' || s[3== '/') {
    26.         if (s[3== 'x') {
    27.             b = b * c;
    28.         } else {
    29.             b = b / c;
    30.         }
    31.         ss << b;//类型转换
    32.         temp = ss.str(); //完成类型转换
    33.         str += s.substr(02);
    34.         str += temp;
    35.         str += s.substr(5);
    36.     } else if (s[5== 'x' || s[5== '/') {
    37.         if (s[5== 'x') {
    38.             c = c * d;
    39.         } else {
    40.             c = c / d;
    41.         }
    42.         ss << c;//类型转换
    43.         temp = ss.str(); //完成类型转换
    44.         str += s.substr(04);
    45.         str += temp;
    46.     }
    47.     if (str == "") {    //没有进行乘除运算
    48.         if (s[1== '+') {
    49.             a = a + b;
    50.         } else {
    51.             a = a - b;
    52.         }
    53.         ss << a;//类型转换
    54.         temp = ss.str(); //完成类型转换
    55.         str += temp;
    56.         str += s.substr(3);
    57.     }
    58.     return str;
    59. }

    测试后成功达成目的。

    但是照猫画虎做出来judge_3之后却发现一个缺陷,就是我一开始是直接按照下标去寻找运算符的,但是在进行过一步运算之后发现,部分数值变成了两位的,于是运算符下标也就改变了,所以,应该使用string的STL函数find_first_of来记录对应运算符的位置。

    但是紧接着就要面对如果出现同一个运算符多次出现的时候,其后出现的下标就很难记录了。

    同样的,如果数字不是一位的而是多位的,又要怎么记录呢?

    所以,更换思路。

    思路二(失败)

    首先需要记录数字,不能够使用简单的下标对应了。因为如果出现了形如365*987之类的,就没办法操作了。

    主函数

    同样的,参考思路一的主函数。不再赘述。

    首先读取数字

    返回的ans是数值,k是紧接着的运算符

    1. int get_num(string str, int &k) { // 从k开始一直读所有的数字字符
    2.     int ans = 0;//记录数值
    3.     char chh = str[k];//记录第一个字符,后面判断是否是负号
    4.     if (str[k] >= '0' && str[k] <= '9')
    5.         ans = ans * 10 + str[k] - '0';
    6.     k++;
    7.     for (; k < str.size(); k++) {
    8.         if (str[k] >= '0' && str[k] <= '9')
    9.             ans = ans * 10 + str[k] - '0';
    10.         else break;
    11.     }
    12.     // 此时的k是之后的运算符下标
    13.     k--;//对应在judge_2函数体里的i++
    14.     if (chh == '-') {
    15.         return ans * (-1);
    16.     } else {
    17.         return ans;
    18.     }
    19. }

    读取运算符之后分别保存起来

    1. string judge_3(string s) {
    2.     stack<double> s;//为了防止出现4/5的情况 
    3.     int a, b, c, d;//四个数值 
    4.     int k = 0;//辅助记录下标的 
    5.     string str = "";
    6.     int arr[3= {000};//记录运算符的,加减乘除,对应1,2,3,4 
    7.     a = get_num(s, k);
    8.     arr[0= s[k];
    9.     b = get_num(s, k);
    10.     arr[1= s[k];
    11.     c = get_num(s, k);
    12.     arr[2= s[k];
    13.     d = get_num(s, k);
    14.     return str;
    15. }

    此路不通

    最后对应的去判断是否压入堆栈还需要另一遍的遍历,就觉得好繁琐,肯定是有更合适的思路。如果一边找数值一边压入堆栈呢?

    思路三(失败)

    主函数和数值查询

    参考思路一和思路二

    我想把运算符判断和最后的堆栈压入结合在一起,于是在网上参考资料,找到了新思路。

    最后的函数体

    函数体judge_2来完成压栈判断以及最后的累和

    1. string judge_2(string s){
    2.     stringstream ss;
    3.     stack<double> st;//为了防止出现4/5的情况 
    4.     string str="";
    5.     int num;//保存数值的临时量 
    6.     char ch;//保存运算符的临时量 
    7.     for (int i=0;i<s.size();i++) {//i辅助记录下标的
    8.         if ((s[i]>='0'&&s[i]<='9')||s[i]=='-'||s[i]=='+')  {//是正是负或者是数值 
    9.             num=get_num(s,i);
    10.             st.push((double)num);
    11.         }
    12.         else {
    13.             ch=s[i];
    14.             double x1=st.top();
    15.             st.pop();
    16.             double x2=get_num(s,i);
    17.             if (ch=='x')
    18.                 st.push((double)x1*(double)x2);
    19.             else
    20.                 st.push((double)x1/(double)x2);
    21.         }
    22.     }
    23.     int sum=0;
    24.     while (!st.empty()) {
    25.         sum+=st.top();
    26.         st.pop();
    27.     }
    28.     if(sum==24){
    29.         str="YES";
    30.     }else{
    31.         str="NO";
    32.     }
    33.     // ss<<sum;
    34.     // 
    35.     // str=ss.str();
    36.     return str;
    37. }

    在这里能够成功的运行出来想要的结果!

    成功1

    内心里泪流满面!

    但是测试之后...

    空间1

    空间太大爆掉了?

    我试了试我参考的代码,切,原来他的也过不去....

    空间2

    最后还是我找伙伴寻求帮助,终于能够通过了!

    感谢

    从今以后,所有刷题的文章都是先写正确的在前面,后面再附上我之前的思考和失败过程。

    源码文件:

    gitee:https://gitee.com/JunKuangKuang/KeenCPPTest-all/tree/main/ccf/2019-03/2

    github:https://github.com/JunKuangKuang/KeenCPPTest-all/tree/main/ccf/2019-03/2

    感谢现在努力的自己。

    感谢俺的亲亲舍友,诶嘿嘿嘿

    第十六次 ccf 201903-2 二十四点,这篇文章里还写了如果遇到括号怎么办!

    波兰式、逆波兰式与表达式求值,可以读读了解基础知识

  • 相关阅读:
    Ubuntu安装cuda
    HTTP 连接详解
    掌握C语言文件操作:从入门到精通的完整指南!
    这些 git 高级命令你知道几个
    MySQL——索引优化,索引机制,索引类型及其使用
    代码随想录刷题|LeetCode 300.最长递增子序列 674. 最长连续递增序列 718. 最长重复子数组
    Elasticsearch
    前端正则校验
    快手直播显示请求过快
    Redisson 集成SpringBoot 详解
  • 原文地址:https://blog.csdn.net/qq_41461536/article/details/127748088