鱼C论坛

 找回密码
 立即注册
查看: 2787|回复: 13

[已解决]【C++板块提升计划】梦想护卫舰 第20关 逻辑表达式

[复制链接]
发表于 2023-2-4 07:56:59 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 zhangjinxuan 于 2023-5-22 18:18 编辑

上一关:铺地毯


梦想护卫舰 第20关 逻辑表达式


你们的聪明才智惊住了他们,不过他们还是不服气

打算用一个逻辑表达式来难住你们

在一个逻辑表达式中,元素的值只有两种可能:0(表示假)和 1(表示真)。元素之间有多种可能的逻辑运算,本题中只需考虑如下两种:“与”(符号为 &)和“或”(符号为 |)。其运算规则如下:
  1. 0&0=0 0&1=0 1&0=0 1&1=1
  2. 0|0=0 0|1=1 1|0=1 1|1=1
复制代码


在一个逻辑表达式中还可能有括号。规定在运算时,括号内的部分先运算;两种运算并列时,& 运算优先于 | 运算;同种运算并列时,从左向右运算。

比如,表达式 0|1&0 的运算顺序等同于 0|(1&0);表达式 0&1&0|1 的运算顺序等同于 ((0&1)&0)|1。

此外,在 C++ 等语言的有些编译器中,对逻辑表达式的计算会采用一种“短路”的策略:在形如 a&b 的逻辑表达式中,会先计算 a 部分的值,如果 a=0,那么整个逻辑表达式的值就一定为 0,故无需再计算 b 部分的值;同理,在形如 a|b 的逻辑表达式中,会先计算 a 部分的值,如果 a=1那么整个逻辑表达式的值就一定为 1,无需再计算 b 部分的值。

现在给你一个逻辑表达式,你需要计算出它的值,并且统计出在计算过程中,两种类型的“短路”各出现了多少次。需要注意的是,如果某处“短路”包含在更外层被“短路”的部分内则不被统计,如表达式 1|(0&1) 中,尽管 0&1 是一处“短路”,但由于外层的 1|(0&1) 本身就是一处“短路”,无需再计算 0&1 部分的值,因此不应当把这里的 0&1 计入一处“短路”。

输入格式
一个字符串,表示表达式

输出格式
输出共两行,第一行输出一个字符 0 或 1,表示这个逻辑表达式的值;第二行输出两个非负整数,分别表示计算上述逻辑表达式的过程中,形如 a&b 和 a|b 的“短路”各出现了多少次。

输入样例1
  1. 0&(1|0)|(1|1|1&0)
复制代码


输出样例1
  1. 1
  2. 1 2
复制代码


输入样例2
  1. (0|1&0|1|1|(1|1))&(0&1&(1|0)|0|1|0)&0
复制代码


输出样例2
  1. 0
  2. 2 3
复制代码


数据范围
对于所有数据,保证1 <= n <= 1e6,且字符串是一个合法的逻辑表达式

注意:本题非原创,转载于 CSP-J 2022 第三题,题解个人原创

C/C++时间限制:1000ms
C/C++空间限制:512mb
其他语言时间限制:2000ms
其他语言空间限制:1024mb


                               
登录/注册后可看大图


答案与解析
游客,如果您要查看本帖隐藏内容请回复
[/hide]


最佳战士排行榜
第一名第二名第三名
名字
链接
语言
效率
代码得分
综合得分
奖励5鱼币5荣誉+“最佳答案(另一贴)”3鱼币3荣誉+"最佳答案"(本贴)2鱼币2荣誉

综合评分会参照运行时间(代码效率),代码长度,代码可读性,解题思路,代码得分等来进行评分


                               
登录/注册后可看大图


下一关:解题

创作不易,如果你喜欢,别忘了分、顶


最佳答案
2023-2-4 11:05:45
看看

评分

参与人数 1鱼币 +1 收起 理由
梦想护卫舰官方 + 1 感谢楼主无私奉献!

查看全部评分

本帖被以下淘专辑推荐:

小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2023-2-4 09:00:29 | 显示全部楼层
研究研究, 先抢个楼先
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-2-4 11:05:45 | 显示全部楼层    本楼为最佳答案   
看看
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2023-2-4 11:55:34 | 显示全部楼层
好奇怪的算法,有点看不懂两个样例的意思(尤其是第二个)
按照 C 的标准样例一似乎应该只有一个 and_skip 和一个 or_skip,只有第一个 0 和第二个括号中的第一个 1 会被求值
一些非常朴素的实验
  1. #include <stdio.h>
  2. #include <stdbool.h>
  3. #define eval_helper(name, value) int name;bool f_##name(){name = 1; return value;}
  4. eval_helper(a, false);
  5. eval_helper(b, true);
  6. eval_helper(c, false);
  7. eval_helper(d, true);
  8. eval_helper(e, true);
  9. eval_helper(f, true);
  10. eval_helper(g, false);
  11. int main(){
  12.     if(f_a() && (f_b() || f_c()) || (f_d() || f_e() || f_f() && f_g())) printf("!\n");
  13.     printf("%d %d %d %d %d %d %d\n", a, b, c, d, e, f, g);
  14.     return 0;
  15. }
复制代码


一个不正确的重量级解法,既然写了就发上来吧
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <stdbool.h>
  4. struct eval_environment{
  5.     size_t or_skip;
  6.     size_t and_skip;
  7. };
  8. struct tree_node{
  9.     bool (*eval)(struct tree_node* target, struct eval_environment* environment);
  10.     void (*release)(struct tree_node* target);
  11.     void (*print)(struct tree_node* target, FILE* stream);
  12. };
  13. struct node_list{
  14.     struct tree_node* node;
  15.     struct node_list* next;
  16. };
  17. struct binary_expression_node{
  18.     struct tree_node tree_node;
  19.     struct node_list* children;
  20.     struct node_list* last_children;
  21. };
  22. bool and_eval(struct tree_node* target, struct eval_environment* environment){
  23.     struct binary_expression_node* node = (struct binary_expression_node*)target;
  24.     bool result = true;
  25.     for(struct node_list* child = node->children; child != NULL; child = child->next){
  26.         result = result && child->node->eval(child->node, environment);
  27.         if(result == false && child != node->last_children){
  28.             environment->and_skip += 1;
  29.             break;
  30.         }
  31.     }
  32.     return result;
  33. }
  34. bool or_eval(struct tree_node* target, struct eval_environment* environment){
  35.     struct binary_expression_node* node = (struct binary_expression_node*)target;
  36.     bool result = false;
  37.     for(struct node_list* child = node->children; child != NULL; child = child->next){
  38.         result = result || child->node->eval(child->node, environment);
  39.         if(result == true && child != node->last_children){
  40.             environment->or_skip += 1;
  41.             break;
  42.         }
  43.     }
  44.     return result;
  45. }
  46. void binary_print(struct tree_node* target, char op, FILE* stream){
  47.     struct binary_expression_node* node = (struct binary_expression_node*)target;
  48.     fprintf(stderr, "(");
  49.     bool begin = true;
  50.     for(struct node_list* child = node->children; child != NULL; child = child->next){
  51.         if(begin) begin = false;
  52.         else fprintf(stream, " %c ", op);
  53.         child->node->print(child->node, stream);
  54.     }
  55.     fprintf(stderr, ")");
  56. }
  57. void and_print(struct tree_node* target, FILE* stream){
  58.     binary_print(target, '&', stream);
  59. }
  60. void or_print(struct tree_node* target, FILE* stream){
  61.     binary_print(target, '|', stream);
  62. }
  63. void binary_release(struct tree_node* target){
  64.     struct binary_expression_node* node = (struct binary_expression_node*)target;
  65.     struct node_list* next = NULL;
  66.     for(struct node_list* child = node->children; child != NULL; child = next){
  67.         next = child->next;
  68.         child->node->release(child->node);
  69.         free(child);
  70.     }
  71.     free(target);
  72. }
  73. void binary_attach_child(struct binary_expression_node* node, struct tree_node* child){
  74.     struct node_list* l = malloc(sizeof(struct node_list));
  75.     l->node = child;
  76.     l->next = NULL;
  77.     node->last_children->next = l;
  78.     node->last_children = l;
  79. }
  80. struct value_expression_node{
  81.     struct tree_node tree_node;
  82.     bool value;
  83. };
  84. bool value_eval(struct tree_node* target, struct eval_environment* environment){
  85.     struct value_expression_node* node = (struct value_expression_node*)target;
  86.     return node->value;
  87. }
  88. void value_release(struct tree_node* target){
  89.     free(target);
  90. }
  91. void value_print(struct tree_node* target, FILE* stream){
  92.     struct value_expression_node* node = (struct value_expression_node*)target;
  93.     fprintf(stream, "%d", node->value);
  94. }
  95. struct tree_node* make_or_node(char** input);
  96. struct tree_node* make_and_node(char** input);
  97. struct tree_node* make_unary_node(char** input);
  98. struct tree_node* make_value_node(char** input);
  99. struct tree_node* make_or_node(char** input){
  100.     struct tree_node* sub_node = make_and_node(input);
  101.     if(**input != '|') return sub_node;
  102.     struct binary_expression_node* node = malloc(sizeof(struct binary_expression_node));
  103.     node->tree_node.eval = or_eval;
  104.     node->tree_node.release = binary_release;
  105.     node->tree_node.print = or_print;
  106.     node->children = malloc(sizeof(struct node_list));
  107.     node->children->node = sub_node;
  108.     node->children->next = NULL;
  109.     node->last_children = node->children;
  110.     while(**input == '|'){
  111.         *input += 1;
  112.         sub_node = make_and_node(input);
  113.         binary_attach_child(node, sub_node);
  114.     }
  115.     return (struct tree_node*)node;
  116. }
  117. struct tree_node* make_and_node(char** input){
  118.     struct tree_node* sub_node = make_unary_node(input);
  119.     if(**input != '&') return sub_node;
  120.     struct binary_expression_node* node = malloc(sizeof(struct binary_expression_node));
  121.     node->tree_node.eval = and_eval;
  122.     node->tree_node.release = binary_release;
  123.     node->tree_node.print = and_print;
  124.     node->children = malloc(sizeof(struct node_list));
  125.     node->children->node = sub_node;
  126.     node->children->next = NULL;
  127.     node->last_children = node->children;
  128.     while(**input == '&'){
  129.         *input += 1;
  130.         sub_node = make_unary_node(input);
  131.         binary_attach_child(node, sub_node);
  132.     }
  133.     return (struct tree_node*)node;
  134. }
  135. struct tree_node* make_unary_node(char** input){
  136.     if(**input == '('){
  137.         *input += 1;
  138.         struct tree_node* result = make_or_node(input);
  139.         *input += 1;
  140.         return result;
  141.     }else{
  142.         return make_value_node(input);
  143.     }
  144. }
  145. struct tree_node* make_value_node(char** input){
  146.     struct value_expression_node* node = malloc(sizeof(struct value_expression_node));
  147.     node->tree_node.eval = value_eval;
  148.     node->tree_node.release = value_release;
  149.     node->tree_node.print = value_print;
  150.     if(**input == '0') node->value = false;
  151.     else node->value = true;
  152.     *input += 1;
  153.     return (struct tree_node*)node;
  154. }
  155. void clear_input(char* buffer){
  156.     char* next = buffer;
  157.     while(*buffer != '\0'){
  158.         if(
  159.             *buffer == '0'
  160.             || *buffer == '1'
  161.             || *buffer == '('
  162.             || *buffer == ')'
  163.             || *buffer == '&'
  164.             || *buffer == '|'
  165.         ) *next++ = *buffer;
  166.         buffer++;
  167.     }
  168.     *next = '\0';
  169. }
  170. int main(){
  171.     enum{ BufferSize = 2000000 };
  172.     char* buffer = malloc(BufferSize);
  173.     size_t real_size = fread(buffer, 1, BufferSize, stdin);
  174.     buffer[real_size] = '\0';
  175.     char* input = buffer;
  176.     clear_input(buffer);
  177.     fprintf(stderr, "[%s]\n", buffer);
  178.     struct tree_node* expression_tree = make_or_node(&input);
  179.     expression_tree->print(expression_tree, stderr);
  180.     fprintf(stderr, "\n");
  181.     struct eval_environment environment = { .or_skip = 0, .and_skip = 0 };
  182.     int result = expression_tree->eval(expression_tree, &environment);
  183.     printf("%d\n%zu %zu\n", result, environment.and_skip, environment.or_skip);
  184.     expression_tree->release(expression_tree);
  185.     free(buffer);
  186.     return 0;
  187. }
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-2-4 12:16:52 | 显示全部楼层
dolly_yos2 发表于 2023-2-4 11:55
好奇怪的算法,有点看不懂两个样例的意思(尤其是第二个)
按照 C 的标准样例一似乎应该只有一个 and_skip ...

只有20分:https://www.luogu.com.cn/record/101402602
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-2-4 12:48:56 | 显示全部楼层
zhangjinxuan 发表于 2023-2-4 12:16
只有20分:https://www.luogu.com.cn/record/101402602

符合预期,这对于这道题而言是一个错误的算法
(这道题本身的逻辑就很奇怪)
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-2-4 13:59:15 | 显示全部楼层
dolly_yos2 发表于 2023-2-4 12:48
符合预期,这对于这道题而言是一个错误的算法
(这道题本身的逻辑就很奇怪)

小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-2-4 15:05:01 | 显示全部楼层
P8815,完全没思路的
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-2-5 16:28:00 | 显示全部楼层
好像不是原创……
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-2-5 17:05:33 | 显示全部楼层
sfqxx 发表于 2023-2-5 16:28
好像不是原创……

所以我没说原创
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-2-5 17:07:00 | 显示全部楼层
是我理解错了吗? 屏幕截图_20230205_170628.png
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-2-5 17:31:57 | 显示全部楼层
sfqxx 发表于 2023-2-5 17:07
是我理解错了吗?

不好意思,我直接从之前抄的格式……
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-2-5 18:18:49 From FishC Mobile | 显示全部楼层
zhangjinxuan 发表于 2023-2-5 17:31
不好意思,我直接从之前抄的格式……

下一关已经出了,但!
在审核
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-2-7 11:43:42 | 显示全部楼层
下一关传送门坏了
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

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

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-4-22 17:45

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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