10 条题解

  • 0
    @ 2023-3-4 12:16:11

    题目分析

    我们需要让计算机计算这一条逻辑表达式的值,并计算短路的个数。

    首先,短路分为两种:

    1. 与短路:0&---------的结果一定是0;

    2. 或短路:1|---------的结果一定是1;

      0&(1|0)|(1|1|1&0)为例​, 短路情况:0& 1| 1|

    其次,我们需要将中缀表达式改写成后缀表达式:

    用一个vector记录后缀表达式sf,用一个stack记录操作符ops;

    具体扫描规则如下

    1. 优先级别:第一级是(),第二级是&,第三级是|
    2. 遇到数字时,将数字push进sf;
    3. 遇到(时,将( push进ops;
    4. 遇到)时,将上一个(前的运算符全部转移到sf中,ops pop掉(。
    5. 遇到运算符时,将运算符转移到sf,直到ops为空或者计算级别不同,再将此运算符push进去。

    最后将剩下的ops全部移到sf中。

    如扫描1|(1|1)&(0&1)​:

    • 扫到1,ops不变,sf为1;
    • 扫到|,ops为|,sf不变;
    • 扫到(,ops为|(,sf不变;
    • 扫到1,ops不变,sf为11;
    • 扫到|,ops为|(|,sf为不变;
    • 扫到1,ops不变,sf为111;
    • 扫到),ops为|,sf为111|;
    • 扫到&,ops为|&,sf不变;
    • 扫到(,ops为|&(,sf不变;
    • 扫到0,ops不变,sf为111|0;
    • 扫到&,ops为|&(&,sf不变;
    • 扫到1,ops不变,sf为111|01;
    • 扫到),ops为|&,sf为111|01&;
    • 最后,sf为111|01&&|

    然后,我们需要将中缀表达式转换成表达式树:

    ​我们需要声明一个结构体数组tr用于存放树的每个节点的值v,左子树位置和右子树位置l和r,声明一个栈sta来缓存每个节点的位置

    所有叶子节点的值都为其对应的数字,用于计算​。​所有非叶子节点的值都为其对应运算符的值,也就是按照运算优先级的顺序:&=2,|=3,所有叶子节点的左子树和右子树位置都为-1,因为叶子结点根本就没有左子树和右子树.

    ​最后,我们通过dfs (深搜)来访问表达式树并计算。

    具体访问规则如下:

    1. 若访问节点的`l`和`r`都是`-1`,直接返回`v`,否则进入第二点;
    2. 计算左节点的数值;
    3. 判断是否出现短路情况,如出现直接返回对应数值;
    4. 计算并返回右节点的数值。

    代码:

    #include<iostream>
    #include<vector>
    #include<stack>
    using namespace std;
    string s;
    const int N=1e6+5;
    struct Node{
           int v,l,r;
    }tr[N];
    int num,ans1,ans2;
    stack<char>ops;
    stack<int>sta;
    vector<char>sf;
    void change()*//* *中缀表达式转后缀表达式* 
    {
           for(int i=0;i<s.size();i++)
           {
                  if(s[i]=='0'||s[i]=='1') sf.push\_back(s[i]);   *​//​*​*扫到数字,直接插入*​*sf*
                  else if(s[i]=='(')  ops.push(s[i]);  *//*  *扫到左边括号,插入运算符栈*
                  else if(s[i]==')') 
                  {
                        while(!ops.empty()&&ops.top()!='(')
                        {
                               sf.push\_back(ops.top());*//* *一直输出到*​​*sf*​​*。直到遇上*​*( *
                               ops.pop();
                        }
                        ops.pop();  *//* *输出多余的(* 
                  } 
                  else if(s[i]=='&')
                  {  *​//​*​*与运算*
                       while(!ops.empty()&&ops.top()=='&')
                         {
                         sf.push\_back(ops.top());
                         ops.pop();
                         }
                         ops.push('&');
                  }
                  else
                  {    *​//​*​*或运算* 
                         while(!ops.empty()&&ops.top()!='(')
                        {
                                sf.push\_back(ops.top());
                                ops.pop();
    
                         }
                         ops.push('|');
                  }
           }
           while (!ops.empty())
           {
                  sf.push\_back(ops.top());
                  ops.pop();
           }
    }
    void build()
    {
           for(int i=0;i<sf.size();i++)
           {
                  if(sf[i]=='1'||sf[i]=='0')
                  {
                        tr[++num]={sf[i]-'0',-1,-1};
                        sta.push(num);
                  }
                  else
                  {
                        int r=sta.top(); sta.pop();
                        int l=sta.top(); sta.pop();
                        int v=(sf[i]=='&'?2:3);
                        tr[++num]={v,l,r};
                        sta.push(num);
                  }
           }
    }
    int dfs(int u)
    {
    ​       if(tr[u].v==0||tr[u].v==1) return tr[u].v; *​//​*​*叶子节点* *。返回数值* 
    ​       int l=dfs(tr[u].l);
           if(l==0&&tr[u].v==2)
           {*//0&*
           ans1++;
              return 0; 
           }
           if(l==1&&tr[u].v==3)
           {*//1|*
                  ans2++;
                  return 1; 
           }
           int r=dfs(tr[u].r);
           return r;
    }
    int main()
    {
           cin>>s;
           change();
           build();
           cout<<dfs(num)<<endl;
           cout<<ans1<<" "<<ans2;
           return 0;
     }
    

    「CSP-J 2022」逻辑表达式(expr)

    信息

    ID
    2918
    时间
    1000ms
    内存
    256MiB
    难度
    8
    标签
    递交数
    156
    已通过
    48
    上传者