10 条题解
-
1
这道题是CSP-J的T3
我会详细的写出解题步骤,尽量让所有人看懂 题面我就不放出来了 那么这道题思路如下↓↓↓
第一步,把中缀表达式转换成后缀表达式
定义
中缀表达式就是正常人使用的表达式,包含括号、数字/变量和运算符,例如
(a+b)*(b-c)-(d-c)
而后缀表达式不需要括号先是数字/变量,遇到运算符后,取出前两个值计算,将计算结果重新存入算式,代替原来的两个数字/变量和运算符,将中缀表达式的例子转换后就是ab+bc-*dc--
需求
首先声明一个vector
sf
用来装后缀表达式,一个栈ops
用来缓存符号,一个字符串s
存输入的表达式 我们要让在同一个维度(括号)内,保持&
在栈的位置比|
高规则
- 优先级:
()
=1,&
=2,|
=3 - 如果是
0
或1
,直接输出到sf
中 - 如果是
(
,存入ops
- 如果是
)
,就将ops
中位于最近的(
之上的所有符号输出进sf
,再删除(
- 如果是
&
,就从栈顶输出优先级≤&
的逻辑运算符到sf
(只有&
)直到栈空或者遇到(
或者遇到|
- 如果是
|
,就从栈顶输出优先级≤|
的逻辑运算符到sf
(有&
和|
)直到栈空或者遇到(
注意,最后
ops
中还剩下一些运算符,要将其全部输出到sf
完成了转换部分,就要为后缀表达式建立表达式树
第二步,建立表达式树
我们需要声明一个结构体数组
tr
用于存放树的每个节点的值v
,左子树位置l
和右子树位置r
,声明一个栈sta
来缓存每个节点的位置所有叶子节点的值都为其对应的数字,用于计算 所有非叶子节点的值都为其对应运算符的值,也就是
&
=2,|
=3 所有叶子节点的左子树和右子树位置都为-1
因为叶子结点根本就没有左子树和右子树
第三步,dfs
我们通过dfs ~~~~(不会有人不知道深度优先搜索吧)~~~~来访问表达式树
dfs规则
- 叶子结点直接返回它的值
v
- 非叶子节点递归获取子树的值来计算
- 非叶子节点通过左子树判断是否出现短路,如果出现短路,直接返回左子树的值,跳过右子树
第四步,ACCODE
现在前三个部分的思路都清楚了,我们直接上代码:
#include<bits/stdc++.h> using namespace std; string s; struct st{ int v,l,r; }tr[1000001]; int num,ans1,ans2;//num是节点数量,ans1和ans2统计两种短路 vector<char>sf;//后缀表达式 stack<char>ops;//符号缓存 stack<int>sta;//节点位置缓存 void change()//中缀to后缀 { for(int i=0;i<s.size();i++) { if(s[i]=='1'||s[i]=='0')//数字直接放入sf { sf.push_back(s[i]); }else if(s[i]=='(')//左括号入栈 { ops.push('('); }else if(s[i]==')')//遇到右括号就将运算符输出到sf直到遇到左括号 { while(ops.top()!='(') { sf.push_back(ops.top()); ops.pop(); } ops.pop();//将无用的左括号出栈 }else if(s[i]=='&')//遇到&就将前面的&输出到sf直到栈空或者遇到其他符号 { while(!ops.empty()&&ops.top()=='&') { sf.push_back(ops.top()); ops.pop(); } ops.push('&');//将当前的&入栈 }else//只剩下|的情况了,将前面的&和|输出到sf直到栈空或者遇到左括号 { 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')//数字存入叶子节点,值就是sf中对应的值 { tr[++num]=(st){sf[i]-'0',-1,-1};//没有子树 sta.push(num);//将节点位置入栈 }else//运算符作为非叶子节点要获取两个子节点 { int v,r,l; r=sta.top(),sta.pop();//从栈顶取出两个节点作为子节点 l=sta.top(),sta.pop(); v=(sf[i]=='&'?2:3);//三目运算符,如果是&,值为2,否则为3 tr[++num]=(st){v,l,r}; sta.push(num);//将节点位置入栈 } } } int dfs(int b)//开始运算 { if(tr[b].v==1||tr[b].v==0)//如果是叶子节点,那么返回节点的值 { return tr[b].v; } int l=dfs(tr[b].l);//递归获取左子树返回值 if(l==0&&tr[b].v==2)//如果是&且满足&的短路条件,短路加一并且直接返回 { ans1++; return 0; } if(l==1&&tr[b].v==3)//这里是判断|的短路 { ans2++; return 1; } int r=dfs(tr[b].r);//获取右子树返回值 return r;//不满足短路,那么返回值为右子树的返回值 } int main() { cin>>s; change();//中缀->后缀 build();//建立表达式树 cout<<dfs(num)<<endl;//从根节点进入dfs,dfs后的返回值就是最终结果 cout<<ans1<<" "<<ans2;//注意输出必须分成两次,否则短路的统计输出为0 return 0; }
以上是本蒟蒻的代码,希望您能看懂,如果有错,欢迎指出,有问题欢迎提问
- 优先级:
信息
- ID
- 2918
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 8
- 标签
- 递交数
- 156
- 已通过
- 48
- 上传者