信息学奥赛复赛复习10-CSP-J2020-03表达式求值-栈、后缀表达式、isdigit函数、c_str函数、atoi函数、链式前向星、数据结构、深度优先搜索

news/2024/10/3 16:57:30
PDF文档公众号回复关键字:20241003

1 P7073 [CSP-J2020] 表达式

[题目描述]

小 C 热衷于学习数理逻辑。有一天,他发现了一种特别的逻辑表达式。在这种逻辑表达式中,所有操作数都是变量,且它们的取值只能为 0 或 1,运算从左往右进行。如果表达式中有括号,则先计算括号内的子表达式的值。特别的,这种表达式有且仅有以下几种运算

与运算:a & b。当且仅当 a和 b 的值都为 1 时,该表达式的值为 1。其余情况该表达式的值为 0

或运算:a | b。当且仅当 a 和 b的值都为 0 时,该表达式的值为 0。其余情况该表达式的值为 1

取反运算:!a。当且仅当 a 的值为 0 时,该表达式的值为 1。其余情况该表达式的值为 0

小 C 想知道,给定一个逻辑表达式和其中每一个操作数的初始取值后,再取反某一个操作数的值时,原表达式的值为多少

[输入格式]

第一行包含一个字符串 s,表示上文描述的表达式。
第二行包含一个正整数 n,表示表达式中变量的数量。表达式中变量的下标为 1,2,⋯ ,n
第三行包含 n 个整数,第 i个整数表示变量 xi 的初值。
第四行包含一个正整数 q,表示询问的个数。
接下来 q 行,每行一个正整数,表示需要取反的变量的下标。注意,每一个询问的修改都是临时的,即之前询问中的修改不会对后续的询问造成影响。
数据保证输入的表达式合法。变量的初值为 0 或 1

[输出格式]

输出一共有 q 行,每行一个 0 或 1,表示该询问下表达式的值

[输入输出样例]

输入 #1

x1 x2 & x3 |
3
1 0 1
3
1
2
3

输出 #1

1
1
0

输入 #2

x1 ! x2 x4 | x3 x5 ! & & ! &
5
0 1 0 1 1
3
1
3
5

输出 #2

0
1
1

说明/提示

该后缀表达式的中缀表达式形式为 (x1and⁡x2)or⁡x3。

对于第一次询问,将 x1 的值取反。此时,三个操作数对应的赋值依次为 0,0,1。原表达式的值为 (0&0)∣1=1

对于第二次询问,将 x2 的值取反。此时,三个操作数对应的赋值依次为 1,1,1。原表达式的值为 (1&1)∣1=1

对于第三次询问,将 x3 的值取反。此时,三个操作数对应的赋值依次为 1,0,0。原表达式的值为 (1&0)∣0=0

2 相关知识点

1) isdigit函数

在C语言中,isdigit()函数是用来检查一个字符是否为数字字符(0-9)的

#include <stdio.h>
#include <ctype.h>int main() {char ch;printf("请输入一个字符:");scanf("%c", &ch);if (isdigit(ch)) {printf("%c 是一个数字字符。\n", ch);} else {printf("%c 不是一个数字字符。\n", ch);}return 0;
}
/*
输入 
请输入一个字符:4
输出 
4 是一个数字字符。
输入 
请输入一个字符:r
输出 
r 不是一个数字字符。
*/

2) c_str函数

c_str() 是 C++ 中的一个成员函数,用于将 std::string 对象转换为 C 风格的字符串(即以 null 结尾的字符数组)

#include <iostream>
#include <string>
using namespace std;int main() {string str = "Hello, world!";const char* c_str = str.c_str();cout << "C-style string: " << c_str << endl;return 0;
}

3) atoi函数

atoi() 是 C 语言中的一个标准库函数,用于将字符串转换为整数

#include <stdio.h>
#include <stdlib.h>int main() {char str[] = "12345";int num = atoi(str);printf("转换后的整数为:%d\n", num);return 0;
}

3 思路分析

1 使用栈计算后缀表达式的值,遇到操作数存入栈中,遇到操作符从栈中取出计算
2 构建二叉树遇到操作符时,从栈中取出对应操作数,建立操作符和操作数的边
3 通过dfs逐一判断每个操作数变化对结果是否有影响如果是非操作符(!) ,影响前面1个操作符,且此操作符变化对结果一定有影响如果是与操作符(&),如果1个操作数为1,另外1个操作符变化对结果有影响如果是或操作符(|),如果1个操作费为0,另外1个操作符变化对结果有影响
示例
x1 x2 & x3 |
3
1 0 1
x1和x2的操作符为&
x1为1时,x2为0时,结果为0
x1为1时,x2为1时,结果为1
因此x2变化对结果有影响,x1变化对结果无影响&这个分支计算结果和x3的操作符为|
x3为1时,&这个分支对结果无影响

示例程序

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;//表达式最大长度 
int num[N];//存储每个节点的值
char c[N];//存储运算符
int m;//表示c数组的长度 
bool f[N];//存储每个节点的值修改后对表达式的值是否有影响
struct node{/*to 边去向的结点next 下一条边,连接以1条边为起点的所有的边 */int to,next; 
}a[N]; 
/*head 的下标为起点 head的值为以head下标为起点的最后一条边 k存储a数组的长度
*/ 
int head[N],k=0;
stack<int> st;//栈 存储后缀表达式的操作数 
int n;//n个操作数 
string s;//读入表达式 
/*
链式前向星建边
u为起点 v为终点 
*/ 
void add(int u,int v){k++;//每条边存入a数组 k为下标 a[k].to=v;//终点 a[k].next=head[u];//下一个结点指向u为起点的上一条边 head[u]=k;//u为起点的边指向本次新增的边 
} 
/*
深搜计算哪些结点的值修改后会影响结果
从根遍历 x开始 
深度优先搜索二叉树,每次只改变1位
把修改可能影响结果的位都做标识
!对应操作数一定会影响
& 如果1个操作数是1,另外1个对结果会产生影响
| 如果1个操作数是0,另外1个对结果会产生影响 
*/ 
void dfs(int x){f[x]=true;//只会深搜值取反后会影响结果的节点if(x<=n) return;//遇到叶子搜索结束/*如果是!,head[x]找出x的下标a[head[x]] 找出x对应边a[head[x]].to,找出x对应边的终点 */if(c[x]=='!') dfs(a[head[x]].to);else{//& | 拿到2个子结点的编号// 找出x对应边的终点int n1 = a[head[x]].to;//x连接第1个结点 /*存图使用链式前向星,x连接的结点通过链表连在一起a[head[x]]表示x指向的第1条边a[head[x]].next表示x指向下1条边起点a[a[head[x]].next]表示x指向下1条边a[a[head[x]].next].to表示x指向下1条边终点 */ int n2=a[a[head[x]].next].to;//x连接第2个结点 if(c[x]=='&'){//如果x对应操作符是&/*第1个结点操作数是1,第2个操作数影响结果例如: 1&1=11&0=0 */if(num[n1]==1) dfs(n2);if(num[n2]==1) dfs(n1);}else if(c[x]=='|'){/*第1个结点操作数是0,第2个操作数影响结果例如: 0|1=10&0=0 */if(num[n1]==0) dfs(n2);if(num[n2]==0) dfs(n1);}} 
} int main()
{getline(cin,s);//读入表达式 scanf("%d",&n);//输入n个运算数的值for(int i=1;i<=n;i++){//逐一读入运算数 scanf("%d",&num[i]);} string w="";//存储连续的数字 int x,y;//x第1个操作数 y第2个操作数 m=n;//c数组从n+1开始存储运算符 for(int i=0;i<s.size();i++){//采用连续性元素统计的思想,统计连续的数字字符为运算数的下标if(isdigit(s[i])){w = w +s[i];//如果连续数字结束了if(i==s.size()-1 || !isdigit(s[i+1])){//运算数入栈st.push(atoi(w.c_str()));w= "";}}else if(s[i]=='!'){m++;c[m]=s[i];//将运算符存入c数组//取1个栈顶元素计算,并将结果入栈x = st.top();st.pop();num[m]=!num[x];st.push(m);//建树add(m,x); }else if(s[i]=='&' || s[i]=='|'){//将运算符存入c数组m++;c[m]=s[i]; //取2个栈顶元素计算,并将结果入栈x = st.top();st.pop();y = st.top();st.pop();if(s[i]=='&') num[m]=num[x] & num[y];else if(s[i]=='|') num[m]=num[x] | num[y];st.push(m);//建树 建操作符到2个操作数的2条边 add(m,x);add(m,y);}} int r=st.top();//根结点存储了表达式计算结果下标 int ans = num[r];//num数组找到表达式下标的值 //深搜计算那些结点的值发生修改会影响结果,存储f数组 dfs(r);int q;cin>>q;//输入q次询问 while(q--){//循环每一次询问 scanf("%d",&x);//读入每次取反的下标//如果本次改变对结果有影响取反 if(f[x]==true) printf("%d\n",!ans); else printf("%d\n",ans);//否则结果不变 }return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ryyt.cn/news/67404.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

群晖docker实现稍后阅读wallabag

开篇 本文基于 docker 和 github 开源项目 wallabag 关于群晖安装, 在项目的说明文档里面显示他们在群晖社区里面提供了一个套件, 但我在添加社区以后并没有找到, 所以采用了 docker 方式 拉取镜像Ssh 链接群晖, sudo -i 进入 root 权限 使用命令 docker run -v /opt/wallabag/…

bing chat 该服务在你所在的地区不可用。

一是:在浏览器搜索结果页-更多中,将国家或地区更改为非中国大陆。 二是:在浏览器设置-语言中,将语言更改为非中文简体的语言,这里语言是可以更改回来。 三是:重新注册一个新的Microsoft 账号,推荐谷歌邮箱进行注册。编程是个人爱好

[错误代码]SQLSTATE[HY000] [1045] Access denied for user 20241001@localhost (using password: YES)

这个错误提示 SQLSTATE[HY000] [1045] Access denied for user 20241001@localhost (using password: YES) 表示 MySQL 认证失败,通常是由于用户名或密码不正确导致的。 解决方法检查用户名和密码 确认使用的用户名和密码是否正确。重置密码 如果忘记密码,可以重置密码。检查…

国庆快乐!附ssh实战

小伙伴们,有一段时间没更新了,目前在中科院软件所实习,在这里我祝大家国庆快乐!今天这一期带来ssh命令的实战教程,ssh在工作当中遇到的非常多,因为总是需要登服务器,而且玩法也有不少,这是我常用的几个玩法。 1、Windows直接连接虚拟机启动的Linux。 ssh user@IPV42、从…

当前页面出现致命错误,详细报错请切换至开发模式调试

切换到开发模式:获取详细的错误信息。 检查列定义:确认 Color 列的定义是否合理。 修改列定义:如果需要,增加列的长度。 重新导入数据:确保数据符合新的列定义。希望这些步骤能帮助你解决问题。如果有更多详细的信息,请随时提供。扫码添加技术【解决问题】专注中小企业网…

【软考】2 码制 / 机器数

概念 机器数只能以二进制方式表示,大类分为【无符号数】和【有符号数】 【无符号数】在机器数中没有符号,表示正数 【有符号数】在机器数中有符号,包含正数的其他数值,存在四种操作:【原码】【反码】【补码】【移码】 一、原码 最高位作为符号位进行正数和负数表示 剩余低…

基于selenium的爬取dblp论文的python爬虫

出于阅读文献的需要,导师让我写一个能够爬取dblp上文献资料的爬虫,话不多说,开学。 学习路径总结前端基本知识 request库与bs库 目标特征,规划爬取步骤 动态加载的应对方法-selenium前端基本知识 前端开发是指创建Web页面或应用程序用户可以与之交互的部分。前端开发主要涉…

探索 java 中的各种锁

Java 8+ -序章 一直听说 java 的各种锁、(线程)同步机制,一直没有深入探索。 最近多看了几篇博文,算是理解的比较深入一些了,特写本文做个记录。ben发布于博客园锁是什么? 一种用于 多个线程运行时协调的机制。 作用如下:ben发布于博客园 1、用于多线程之间同步,比如,…