搜索
热搜: NOIP OIer 神牛
查看: 319|回复: 0

表达式求值(系列问题) CCF CSP-J第三题难度

[复制链接]

主题

帖子

0

积分

新手上路

Rank: 1

积分
0
发表于 2023-8-25 20:36:02 | 显示全部楼层 |阅读模式
本帖最后由 tiger 于 2023-8-25 20:38 编辑

天我们来探讨一下表达式的求值,我们的内容分为三部分:
1.认识表达式
2.表达式计算
3.例题


===================================================
===================================================
  
Ⅰ.认识表达式
喲!康康谁来辣!(出自《信息学基地.oj》------Famer Lei    我没侵权吧
哦,是我们今天的主角------Mr.表达式先生
表达式分为三种:前缀表达式,中缀表达式,后缀表达式
大家喜欢哪种呢?投个票吧!
不不不不不不,很简单,人类喜欢中缀表达式,比如:
1.993*10^18/123^2.28
计算机喜欢前缀和后缀表达式:
*^/^1.993 10 18 123 2.28
1.993 10 18 123 2.28*^/^
表达式还可以抽象成表达式树
前缀表达式是前序遍历的另一种具象的体现,
中缀表达式是中序遍历的另一种具象的体现,
后缀表达式是后序遍历的另一种具象的体现


===================================================
===================================================
  

Ⅱ.表达式计算
很简单,前缀表达式从右至左扫描
后缀表达式从左至右扫描
中缀不用说了

===================================================
===================================================
  


Ⅲ.例题
1349就不说了oj.singera.cn/dist/quesInfo?problem_id=1349
2122小编tiger都没做对oj.singera.cn/dist/quesInfo?problem_id=2122
3638最适合不过了
思路一:
∣s∣=1 有 2 22 种情况:1 11, 0 00
∣ s ∣ = 3 |s|=3∣s∣=3 有 8 88 种情况:1 & 0 1\&01&0、0 & 1 0\&10&1、1 & 1 1\&11&1、0 & 0 0\&00&0、0 ∣ 1 0|10∣1、1 ∣ 1 1|11∣1、1 ∣ 0 1|01∣0、0 ∣ 0 0|00∣0
∣ s ∣ = 5 |s|=5∣s∣=5 时,如果有括号则和 ∣ s ∣ = 3 |s|=3∣s∣=3的情况是一样的,没有括号共有 32 3232 种情况。
可打表或if语句实现,可得 20  分。
详见【CSP2022J-T3】逻辑表达式_2022-csp-j-3-逻辑表达式_sqtiger的博客-CSDN博客
思路二:
if语句,考虑没有括号的情况:
  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. string s;
  4. int ans1 = 0, ans = 0;
  5. int main(){
  6.         cin >> s;
  7.         bool f = false, f1 = true;
  8.         for (int i = 0; i < s.size(); ++i){
  9.                 if (s[i] == '1' || s[i] == '0'){
  10.                         f1 = f1 && (s[i] - '0');
  11.                 } else if (s[i] == '|'){                        
  12.                         f = f || f1;
  13.                         if (f) ans++;
  14.                         f1 = true;
  15.                 } else {
  16.                         if (!f1 && !f) ans1++;
  17.                 }
  18.         }
  19.         f = f || f1;
  20.         cout << f << endl;
  21.         cout << ans1 << " " << ans << endl;
  22.         return 0;
  23. }
复制代码
可得40分
思路三:
用栈跑一个括号匹配,用 vh 来表示标号为 i 的左括号匹配的右括号的位置。
递归求解,dfs(l, r)求区间 [l, r] 内表达式的值。
每个区间记录三个值,1、布尔表达式的值v;2、& \&& 短路的次数 s1;3、∣ |∣ 短路的次数s2.
递归时具体操作
ans用来记录整个区间的值
ans1 用来记录当前& \&&分段的值.
tmp 用来记录当前操作数的值
读到 0 00、1 11、( ((字符,则计算当前操作数。
读到 & \&& 字符,ans1.v值为false,则发生 & \&& 短路,ans1.s1++;否则,将 tmp 值累加到 ans1上。
读到 ∣ |∣ 字符,先像上面将操作数 tmp 累计到 ans1 上;ans.v的值为true,则发生一次 ∣ |∣ 短路,ans.s2++;否则,将 ans1 值累加到 ans 上。
时间复杂度:O ( n ) O(n)O(n),可得100分。

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int MAXN = 2E6 + 10;
  4. struct nod{
  5.         bool v;
  6.         int s1, s2;
  7.         nod(bool _v, int _s1, int _s2): v(_v), s1(_s1), s2(_s2){}
  8. };

  9. string s;
  10. int vh[MAXN];

  11. void readp(){
  12.         cin >> s;
  13.         stack<int>stk;
  14.         for (int i = 0; i < s.size(); ++i){
  15.                 if (s == '(')
  16.                         stk.push(i);
  17.                 else if (s == ')'){
  18.                         vh[stk.top()] = i;
  19.                         stk.pop();
  20.                 }
  21.         }
  22. }

  23. void cal(nod &a, nod b, char op){
  24.         if (op == '&')
  25.                 a = nod(a.v && b.v, a.s1 + b.s1, a.s2 + b.s2);
  26.         else
  27.                 a = nod(a.v || b.v, a.s1 + b.s1, a.s2 + b.s2);
  28. }

  29. nod dfs(int l, int r){
  30.         if (s[l] == '(' && vh[l] == r) return dfs(l + 1, r - 1);;
  31.         nod ans = nod(false, 0, 0), ans1 = nod(true, 0, 0), tmp = nod(true, 0, 0);
  32.         for (int i = l; i <= r; ++i){
  33.                 if (s == '1' || s == '0')
  34.                         tmp = nod(s - '0', 0, 0);
  35.                 else if (s == '(')
  36.                         tmp = dfs(i + 1, vh - 1), i = vh;
  37.                 else if (s == '|'){
  38.                         if (ans1.v) cal(ans1, tmp, '&');
  39.                         else ans1.s1++;
  40.                         if (!ans.v) cal(ans, ans1, '|');
  41.                         else ans.s2++;
  42.                         ans1 = nod(true, 0, 0);
  43.                 }
  44.                 else if (ans1.v) {
  45.                         cal(ans1, tmp, '&');
  46.                 } else ans1.s1++;
  47.         }
  48.         //处理最后一个操作数
  49.         if (ans1.v) cal(ans1, tmp, '&');
  50.         else ans1.s1++;
  51.         //处理最后一段
  52.         if (!ans.v) cal(ans, ans1, '|');
  53.         else ans.s2++;
  54.         return ans;
  55. }

  56. int main(){
  57.         readp();
  58.         nod sol = dfs(0, s.size() - 1);
  59.         cout << sol.v << endl;
  60.         cout << sol.s1 << " " << sol.s2 << endl;
  61.         return 0;
  62. }
复制代码

其他思路欢迎发至邮箱:tiger201303@163.com
今天的内容到此结束
大家下次再见!!!
彩蛋(Willim)
bbs.singera.cn/forum.php?mod=viewthread&tid=370&extra=page%3D1
bbs.singera.cn/forum.php?mod=viewthread&tid=371&extra=page%3D1



回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

津ICP备19006949号-1 | 津公网安备12010102000465号

快速回复 返回顶部 返回列表