主要包括一些中缀、后缀表达式值的计算、表达式是否合法的判断
后缀表达式的讲解:
人工怎么写出中缀表达式的后缀表达式

计算机实现方法:

NOIP and CSP真题
2022 逻辑表达式
这个其实也是在讨论&和|的无用情况,但是要记录整个式子的无用计算次数,所以这里用stack和pair两种结构,自底向上统计无用情况
题解:https://www.cnblogs.com/shirlybaby/p/17803059.html
2020 表达式 http://ybt.ssoier.cn:8088/problem_show.php?pid=2006
这个题要求的是每个元素对总体结果的改变情况,因为在&和|运算中,有的元素值的不同对总体结果没有影响,所以这道题的思路就是建立表达式树,
然后对树上每个元素打上标记,看是否是一个无用的,在打标机的过程的过程中用DFS,而且还要标记下传
题解:https://www.cnblogs.com/shirlybaby/p/17803737.html
1356:计算(calc)----中缀
表达式求值:这里的表达式就是最正常的表达式,有加减乘除,括号等
第一种方法:直接计算,不用转为后缀表达式,边弄边算
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
using namespace std;
//表达式求值,这里的表达式就是最正常的表达式,有加减乘除,括号等
//用一个函数来判断运算符的优先级
int n,m;
int lev(char x)//运算符优先级
{
if(x=='+'||x=='-')//加减的优先级很低
return 1;
if(x=='*'||x=='/')
return 2;
if(x=='^')
return 3;
return 0;//括号的优先级很低
}
void calculate(stack<int> &s1,stack<char> &s2)//弹出栈顶元素并计算//参数是一个运算数的栈和一个运算符的栈
{
/*取出后弹出栈*/
int y=s1.top();
s1.pop();
int x=s1.top();
s1.pop();//弹出两个操作数
char z=s2.top();
s2.pop();//弹出一个操作符
/*根据运算符计算,并压入栈*/
if(z=='+')
s1.push(x+y);
if(z=='-')
s1.push(x-y);//这些也要注意是谁加谁是谁减谁
if(z=='*')
s1.push(x*y);
if(z=='/')
s1.push(x/y);
if(z=='^')
s1.push(pow(x,y));//注意谁是底数,谁是指数
}
char str[1000000];
int main(){
scanf("%s",str+1);
n=strlen(str+1);
stack<int> s1;
stack<char> s2;
int temp=0;
bool flag=false;//这两个参数都是用来临时保存temp和标记是否是数flag的
for(int i=1;i<=n;i++)
{
if('0'<=str[i]&&str[i]<='9')//判断当前字符是否为数字
{
temp=(temp<<3)+(temp<<1)+str[i]-'0';//temp*=10+str[i]-'0'
flag=true;
}
else
{//操作数在这里入栈
if(flag)
{
s1.push(temp);
temp=0;
flag=false;//操作数入栈,数被temp临时保存,这里入栈后temp清零
}
if(str[i]=='(')
{
s2.push(str[i]);
continue;
}
if(str[i]==')')
{
while(s2.top()!='(')//注意这里要判断前一个是不是(,有这种可能性
calculate(s1,s2);
s2.pop();//注意这里还要弹栈,因为有一个(
continue;
}
while(!s2.empty()&&lev(s2.top())>=lev(str[i]))//优先级判断//运算符入栈
calculate(s1,s2);//如果运算符栈不空而且当前的运算符优先级较低,就先算了来(即先计算优先级高的)
s2.push(str[i]);//运算符入栈
}//这一这里面就是一个if-else,分为是否是操作符和是否是操作数
}
if(flag)
{
s1.push(temp);
temp=0;
flag=false;
}
while(!s2.empty())
calculate(s1,s2);
cout<<s1.top()%10000<<endl;
return 0;
}
1358:中缀表达式值(expr)
没有括号,但是需要判断是不是合法的中缀表达式,而且-可能是负数符号(但感觉好像没管??)
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stack>
#include<cstdio>
#define Int stack<int>
#define Char stack<char>
using namespace std;
//这里的用法
Int s1;Char s2;
inline int lev(char x){
if(x=='+'||x=='-') return 1; //用到很多的内联函数,为了节省栈空间
if(x=='*'||x=='/') return 2;
if(x=='^') return 3;
return 0;//数字或括号返回0
}
//快速幂的迭代写法
inline int ksm(int s,int t){
int ans=1;
while(t){
if(t&1) ans*=s;//如果t是奇数
s*=s; //乘以本身,是转化为2进制的写法
t>>=1;//t除以2
}
return ans;
}
//弹栈并且计算
inline void js(Int &s1,Char &s2){
int y=s1.top();s1.pop();
int x=s1.top();s1.pop();//运算数
char c=s2.top();s2.pop();//运算符
if(c=='-') s1.push(x-y);
if(c=='+') s1.push(x+y);
if(c=='*') s1.push(x*y);
if(c=='/') s1.push(x/y);
if(c=='^') s1.push(ksm(x,y));//快速幂
}
inline int c(int x){
return x!=0;//这个函数是用来判断表达式是否合法的,和判断优先级一起用的
}
char sr[100001];
int sum[100001];
int main(){
scanf("%s",sr+1);//注意写法,是从1开始的
int n=strlen(sr+1)-1;//-1是因为去除末尾的@
for(int i=1;i<=n;i++){
sum[i]+=sum[i-1];
if(sr[i]=='(') ++sum[i];
if(sr[i]==')') --sum[i]; //这个for循环是用来匹配检查的,判断合法性,()是否匹配
}
bool out=0;//判断是否存在*/ 等情况
for(int i=2;i<=n;i++){
if(c(lev(sr[i]))&&c(lev(sr[i-1]))){
out=1;
break;
}
}
if(n==1&&c(lev(sr[1]))||sum[n]||out){
cout<<"NO"<<endl;//不合法的三种情况
return 0;
}
//判断完了合法性后就和calc一样了,开始计算
Int s1;
Char s2;
int temp=0,flag=0;
for(int i=1;i<=n;i++){
if(sr[i]>='0'&&sr[i]<='9'){
temp=(temp<<3)+(temp<<1)+sr[i]-'0';//注意前面的写法,等价于temp*10
flag=1;
}
else{
if(flag) {
s1.push(temp);
temp=0;flag=0;
}//先判断是不是数
if(sr[i]=='('){
s2.push(sr[i]);
continue;//推出本次循环
}
if(sr[i]==')'){
while(s2.top()!='(') js(s1,s2);
s2.pop();//然后就弹栈
continue;//退出本次循环
}
while(!s2.empty()&&lev(sr[i])<=lev(s2.top())) js(s1,s2);
s2.push(sr[i]);//运算符入栈
}
}
if(flag){
s1.push(temp);
temp=flag=0;
}
while(!s2.empty()) js(s1,s2);
cout<<s1.top();
return 0;
}
1331:【例1-2】后缀表达式的值
在一本通上面不行了,会出现编译错误,好像是gets函数的原因,不懂!!!!
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdio>
using namespace std;
//栈
char s[256];
int stack[267];//注意stack类型是int,不放运算符
void comp(char s[]){
int top=0,i=0;
int x=0;
while(i<=strlen(s)-2){//因为最后一个是@
switch(s[i]){ //计算后缀表达式:要用到switch
case '+': stack[--top]+=stack[top+1];break;
case '-': stack[--top]-=stack[top+1];break;
case '*': stack[--top]*=stack[top+1];break;
case '/': stack[--top]/=stack[top+1];break;
default: x=0;while(s[i]!=' ') x=x*10+s[i++]-'0';//处理多位数
stack[++top]=x;break;
}
i++;
}//年纪大了:要注意switch的写法
cout<<stack[top]<<endl;
}
int main(){
gets(s);//要用gets()
comp(s);
return 0;
}
1358:中缀表达式值(expr)
中缀表达式的值,还带检查表达式合不合法,注意表达式不合法的三种情况:
1)n==1且第一个是运算符
2)括号不匹配
3)出现连续运算符
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stack>
#include<cstdio>
#define Int stack<int>
#define Char stack<char>
using namespace std;
//这道题既需要判断,也需要计算
//这里的用法
Int s1;Char s2;
inline int lev(char x){
if(x=='+'||x=='-') return 1; //用到很多的内联函数,为了节省栈空间
if(x=='*'||x=='/') return 2;
if(x=='^') return 3;
return 0;//数字或括号返回0
}
//快速幂的迭代写法
inline int ksm(int s,int t){
int ans=1;
while(t){
if(t&1) ans*=s;//如果t是奇数
s*=s; //乘以本身,是转化为2进制的写法
t>>=1;//t除以2
}
return ans;
}
//弹栈并且计算
inline void js(Int &s1,Char &s2){
int y=s1.top();s1.pop();
int x=s1.top();s1.pop();//运算数
char c=s2.top();s2.pop();//运算符
if(c=='-') s1.push(x-y);
if(c=='+') s1.push(x+y);
if(c=='*') s1.push(x*y);
if(c=='/') s1.push(x/y);
if(c=='^') s1.push(ksm(x,y));//快速幂
}
inline int c(int x){
return x!=0;//这个函数是用来判断表达式是否合法的,和判断优先级一起用的
}
char sr[100001];
int sum[100001];
int main(){
scanf("%s",sr+1);//注意写法,是从1开始的
int n=strlen(sr+1)-1;//-1是因为去除末尾的@
for(int i=1;i<=n;i++){
sum[i]+=sum[i-1];
if(sr[i]=='(') ++sum[i];
if(sr[i]==')') --sum[i]; //这个for循环是用来匹配检查的,判断合法性,()是否匹配
}
bool out=0;//判断是否存在*/ 等情况
for(int i=2;i<=n;i++){
if(c(lev(sr[i]))&&c(lev(sr[i-1]))){
out=1;
break;
}
}
if(n==1&&c(lev(sr[1]))||sum[n]||out){
cout<<"NO"<<endl;//不合法的三种情况
//这个就很考验人了:1)n==1 2)第一个是运算符 3)括号不匹配 4)出现连续运算符
return 0;
}
//判断完了合法性后就和calc一样了,开始计算
Int s1;
Char s2;
int temp=0,flag=0;
for(int i=1;i<=n;i++){
if(sr[i]>='0'&&sr[i]<='9'){
temp=(temp<<3)+(temp<<1)+sr[i]-'0';//注意前面的写法,等价于temp*10
flag=1;
}
else{
if(flag) {
s1.push(temp);
temp=0;flag=0;
}//先判断是不是数
if(sr[i]=='('){
s2.push(sr[i]);
continue;//推出本次循环
}
if(sr[i]==')'){
while(s2.top()!='(') js(s1,s2);
s2.pop();//然后就弹栈
continue;//退出本次循环
}
while(!s2.empty()&&lev(sr[i])<=lev(s2.top())) js(s1,s2);
s2.push(sr[i]);//运算符入栈
}
}
if(flag){
s1.push(temp);
temp=flag=0;
}
while(!s2.empty()) js(s1,s2);
cout<<s1.top();
return 0;
}
1353:表达式括号匹配(stack)
#include<iostream>
#include<cstring>
#include<stack>
#include<algorithm>
#include<cstdio>
using namespace std;
string s;
stack<char> ss;
int main(){
cin>>s;
for(int i=0;s[i]!='@';i++){
if(s[i]=='(') ss.push(s[i]);
if(s[i]==')'){
if(!ss.empty()) ss.pop();
else {
cout<<"NO"<<endl;
return 0;
}
}
}
if(!ss.empty()) cout<<"NO"<<endl;
else cout<<"YES"<<endl;
return 0;
}
1354:括弧匹配检验
括弧匹配检验、字符串匹配问题:思想:用数字来表示字符,可以找到正确的规律
char str[10000];
stack<int> S;//用1代表(,2代表),3代表[,4代表]//用数字来代表符号
int main(){
cin>>str;
int len=strlen(str);
for(int i=0;i<len;i++)
{
if(str[i]=='(')//记录左圆括号
S.push(1);
else if(str[i]==')')//记录右圆括号
{
if(S.empty())//栈为空
S.push(2);
else if(S.top()==1)
S.pop();
else
S.push(2);
}
else if(str[i]=='[')//记录左方括号
S.push(3);
else if(str[i]==']')//记录右方括号
{
if(S.empty())//栈为空
S.push(4);
else if(S.top()==3)
S.pop();
else
S.push(4);
}
}
if(S.empty())
printf("OK");
else
printf("Wrong");
return 0;
}
1355:字符串匹配问题(strs)
int n;
char s[256];
int a[256];
char b[256]={0};
void change(char s[]){
for(int i=0;i<strlen(s);i++){
if(s[i]=='{') a[i+1]=1;
if(s[i]=='[') a[i+1]=2;
if(s[i]=='(') a[i+1]=3;
if(s[i]=='<') a[i+1]=4;
if(s[i]=='>') a[i+1]=5;
if(s[i]==')') a[i+1]=6;
if(s[i]==']') a[i+1]=7;
if(s[i]=='}') a[i+1]=8;//将较多的符号转化为数字来判断,找规律:加起来等于9的是合理的
}
}
int main(){
cin>>n;
while(n--){
cin>>s;
change(s);
int t=0;
for(int j=1;j<=strlen(s);j++){
if(a[j]<=4)
if(a[j]>=b[t]) b[++t]=a[j];
else break;
if(a[j]>=5)
if(a[j]+b[t]==9) t--;
else t++;
}
if(t==0) cout<<"YES"<<endl;//还是用栈中元素个数来判断正误
else cout<<"NO"<<endl;
}
return 0;
}
1357:车厢调度(train)
就是模拟弹栈的时候进入的序列是否是合法的序列
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int n;
int a[1001];
int stack[1001];
int main(){
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
int top=0;//记住有这个标志啊
for(int i=1,cur=1;i<=n;i++){
while(cur<=a[i]) stack[++top]=cur++; //第一种情况,需要进栈
if(stack[top]==a[i]) --top;//若在栈顶则弹出(第二种情况,等于)
else {
cout<<"NO"<<endl;//如果不在栈顶,就错误 (第三种情况)
return 0;
}
}
cout<<"YES"<<endl;
return 0;
}
posted on
浙公网安备 33010602011771号