N - DAG优化

Description

大家都学过了代码优化,其中有一个DAG优化,这次我们就练习这个操作。

Input

输入第一行为一个整数n(n < 100),表示该组输入的表达式的个数

之后n行为表达式,每个变量为一个字母,表达式仅包括二元运算 + - * /

例如:A=B+C

Output

通过构造DAG图,进行代码优化,只需要保留AB,删除无用变量,删除变量时,尽量保留最早出现的变量。

PS:保证AB的值不同

Sample

Input

3
A=B+C
B=B+B
A=C+C

Output

B=B+B
A=C+C

本题是使用DAG图进行代码的优化,这个题难就难在怎么让计算机实现这个DAG图,然后筛选无用的代码段做到化简的目的。针对例题进行理解,我会在注释中解释的尽量详细。

理解注释的前提是理解DAG图中结点的表示方法,结点的正下方以及最右方分别代表什么,以及如何根据DAG图重建代码。

#include<bits/stdc++.h>
using namespace std;
string s;
int flag[110]= {0};//flag数组全部初始化为0,flag数组在完成DAG图后,进行代码优化的时候才用到
char ans[1100][1100];//建立一个二维数组,其中行代表第几个表达式,而每一行都有6列,用来存放具体的表达式(最后一列是'\0',表示结束)
int num=0;//贯穿整个代码的全局变量
int n;
struct node {//创建一个结构体 int l=-1,r=-1;//l,r表示DAG图中的左,右子树 char id;//id则表示每一个结点的的值,可以是数字,或者运算符,或者变量名 vector<char>val;//Val表示代码基本块中等号左边的T的下标值
} t[110];
//就比如说一个表达式A=B+C,在DAG图中,建立两个结点n_0,n_1,结点正下方分别存为B,C,之后再建立一个结点,n_2的正右方用来存放A。
//A的左子树指向B,即l=0(n_0);A的右子树指向C,即r=1(n_1)
//n_0的id值为B,n_1的id值为C,而n_2的id值为+
//n_0,n_1的val值为null,n_2的val值为A
//综上:l,r分别代表左右子树结点n的下标值,id表示每个n结点正下方对应的字符,Val则表示每个n结点正右方的字符。
//从此处跳转到 57行主函数进行阅读
int use(int x,char ch) {//use函数相当于判断除了最底层结点之外,其他结点的正右方的Val值
//而t[i].id==ch只可以判断最底层结点的正下方的id值 int len=t[x].val.size();//len等于n结点正右方字符串的长度 for(int i=0; i<len; i++) {//如果正右方存在ch,返回1,否则返回0 if(t[x].val[i]==ch)return 1;}return 0;
}
int add(char ch) {for(int i=num-1; i>=0; i--) {//num初始值为0 if(t[i].id==ch||use(i,ch))return i;//for循环的目的是用于判断在之前所构造的DAG图中是否出现了ch,出现过直接返回结点下标i//t[i].id==ch只用于判断DAG图中的最下层结点,更高层结点是否出现过需要调用use(i,ch)函数判断 //从此处跳转到19行use函数 }t[num].id=ch;//如果没出现过结点,则新建一个结点,此时的num是最新的值,不会出现重复赋值的情况(32行) return num++;//返回主函数进行阅读
}
void add_op(char op,char ch,int l,int r) {//此函数的作用是判断所输入的表达式的等号右边是否重复出现 for(int i=num-1; i>=0; i--) {if(t[i].id==op&&t[i].l==l&&t[i].r==r) {//比如出现了A=B+C与D=B+C,此处判断出等号右边相等,则相等部分忽略 t[i].val.push_back(ch);//只保留等号左边不相等的部分,相当于在DAG图中A存在的结点的正右方加入一个字符D return;//相当于A和D共享一个n结点 }}t[num].id=op;//如果没有重复出现,则新建n结点,结点正下方存入op值 t[num].l=l;//连接左子树 t[num].r=r;//连接右子树 t[num].val.push_back(ch);//将表达式所赋值的字符推入容器 num++;//num继续更新 return;//返回主函数阅读
}
int dfs(int x) {//进行递归 if(t[x].l!=-1&&t[x].r!=-1) {//如果某个结点存在左右子树,flag[x]=1表示要用到这个表达式 flag[x]=1;dfs(t[x].l);//继续遍历,直到最底层的n结点 dfs(t[x].r);}
}
int main() {cin>>n;//输入n的值 for(int i=0; i<n; i++) {//n代表行数,从0到n-1行逐步遍历 cin>>s;//输入表达式 int l=add(s[2]);//每次输入表达式的2号下标的字符记为左子树的值,调用add函数,得到结点n的下标(开头结构体下方有解释) int r=add(s[4]);//每次输入表达式的4号下标的字符记为右子树的值,调用add函数,得到结点n的下标(开头结构体下方有解释)  //从此处跳转到27行add函数进行阅读 add_op(s[3],s[0],l,r);//每次输入的表达式3号下标为运算符,0号下标为表达式所赋值到的字符//运算符,接受运算的字符,左子树的下标,右子树的下标传入add_op函数中进行判断 //从此处跳转到add_op函数进行阅读 }for(int i=0; i<num; i++) {//以上是DAG图的建立,建立好DAG图后开始根据DAG图写重建之后的代码 if(t[i].l!=-1&&t[i].r!=-1) {//如果某个结点存在左右子树 ans[i][0]=t[i].val[0];//以下是对代码重写,重建后的表达式从0-4进行数组的转存,5是结束符 ans[i][1]='=';ans[i][2]=t[t[i].l].val.size()>0?t[t[i].l].val[0]:t[t[i].l].id;ans[i][3]=t[i].id;ans[i][4]=t[t[i].r].val.size()>0?t[t[i].r].val[0]:t[t[i].r].id;ans[i][5]='\0';}}for(int i=num-1; i>=0; i--) {//因为要删除无用变量,只保留AB,所以分别写入AB的for循环判断 if(ans[i][0]=='A') {dfs(i);//跳转到dfs函数 break;}}for(int i=num-1; i>=0; i--) {//同上 if(ans[i][0]=='B') {dfs(i);break;}}for(int i=0; i<num; i++) {//输出 if(flag[i])cout<<ans[i]<<endl;}return 0;
}

上面的代码好像A不了了,老师修改数据了,下面的代码可以A

AC代码:

#include <bits/stdc++.h>
using namespace std;
string s;
int flag[110];
char ans[110][110];
int n,num=0;
struct node
{int l=-1,r=-1;char id;vector<char>val;
}t[110];
int find(int x,char ch)
{for(char c:t[x].val)if(c==ch)return 1;return 0;
}
int add(char ch)
{for(int i=num-1;i>=0;i--)if(ch==t[i].id||find(i,ch))return i;t[num].id=ch;return num++;
}
void add_op(char op,char ch,int l, int r)
{for(int i=num-1;i>=0;i--)if(t[i].id==op&&t[i].l==l&&t[i].r==r){t[i].val.push_back(ch);return;}t[num].id=op;t[num].l=l;t[num].r=r;t[num].val.push_back(ch);num++;
}
void dfs(int x)
{if(t[x].l!=-1){flag[x]=1;dfs(t[x].l);dfs(t[x].r);}
}
char exist(int x)
{char ans=0;for(char c:t[x].val)if(c=='A'||c=='B')ans=c;return ans!=0?ans:t[x].val[0];
}
int main()
{cin>>n;for(int i=0;i<n;i++){cin>>s;int l=add(s[2]);int r=add(s[4]);add_op(s[3],s[0],l,r);}for(int i=0;i<num;i++){if(t[i].l!=-1){ans[i][0]=exist(i);ans[i][1]='=';ans[i][2]=t[t[i].l].val.size()>0?exist(t[i].l):t[t[i].l].id;ans[i][3]=t[i].id;ans[i][4]=t[t[i].r].val.size()>0?exist(t[i].r):t[t[i].r].id;ans[i][5]='\0';}}for(int i=num-1;i>=0;i--){if(ans[i][0]=='A'){dfs(i);break;}}for(int i=num-1;i>=0;i--){if(ans[i][0]=='B'){dfs(i);break;}}for(int i=0;i<num;i++)if(flag[i])cout<<ans[i]<<endl;
}

N - DAG优化SDUT相关推荐

  1. 【编译原理】代码优化,流图/DAG优化

    优化原因 逐条语句进行的代码生成策略经常产生含有大量冗余指令和次最优解结构的目标代码. 代码优化就是被优化程序进行一种语义保持的变换 优化位置 中间代码优化(与机器无关) 目标代码优化(与机器有关) ...

  2. 7-3 DAG图优化-A (15 分)(更新版)

    7-3 DAG图优化-A (15 分) 大家都学过了代码优化,其中有一个DAG优化,这次我们就练习这个操作. 输入格式: 输入第一行为一个整数n(n < 100),表示该组输入的表达式的个数. ...

  3. 7-3 DAG图优化 (15 分)

    7-3 DAG图优化 (15 分) 大家都学过了代码优化,其中有一个DAG优化,这次我们就练习这个操作. 输入格式: 输入第一行为一个整数n(n < 100),表示该组输入的表达式的个数. 之后 ...

  4. 360数据处理平台的架构演进及优化实践

    本文根据DBAplus社群第153期线上分享整理而成 讲师介绍 王素梅 360大数据开发经理 目前在360大数据中心担任大数据开发经理,拥有7年以上大数据行业从业经验,专注大数据处理.大数据平台开发, ...

  5. Apache Spark中的有向无环图DAG

    Apache Spark中的有向无环图DAG 由DATAFLAIR TEAM ·更新· 2018年11月21日 1.目的 在本Apache Spark教程中,我们将了解Apache Spark中的DA ...

  6. Flink SQL 的 9 个示例

    作者:贺小令(晓令) 本文由阿里巴巴技术专家贺小令分享,社区志愿者郑仲尼整理.文章基于 Flink 1.9 版本,从用户的角度来讲解 Flink 1.9 版本中 SQL 相关原理及部分功能变更,希望对 ...

  7. RDD Join 性能调优

    阅读本篇博文时,请先理解RDD的描述及作业调度:[<深入理解Spark 2.1 Core (一):RDD的原理与源码分析 >](http://blog.csdn.net/u01123944 ...

  8. 最佳实践|如何写出简单高效的 Flink SQL?

    摘要:本文整理自阿里巴巴高级技术专家.Apache Flink PMC 贺小令,在Flink Forward Asia 2022 生产实践专场的分享.本篇内容主要分为三个部分: Flink SQL I ...

  9. 【大数据分析】Spark的joins研究

    目录 概述 join的类型 Spark执行join的5种策略 各类join策略的优先级 概述 数据的join操作(数据连接)对于数据分析来说是非常重要的组成部分,不管是Spark Core还是Spar ...

最新文章

  1. python正则匹配_Python正则表达式初识(五)
  2. Error:依赖版本不一致
  3. MySQL调优(三):索引基本实现原理及索引优化,哈希索引 / 组合索引 / 簇族索引等
  4. oracle的口令就是密码吗,如何修改Oracle用户的密码(不改变原密码)
  5. 你代码里的 ThreadLocalRandom,真的安全吗?
  6. 优秀的电商精品素材就到优图
  7. 马克龙宣布15亿欧元投资AI,DeepMind拥吻巴黎
  8. 安全认证框架之Shiro详解
  9. Oracle官网下载速度慢
  10. [境内法规]中国人民银行关于分支行反洗钱工作的指导意见—银发[2005]56号
  11. ApacheCN 活动汇总 2019.7.12
  12. 二元函数泰勒公式例题_泰勒公式与函数展开的操作方法
  13. 基于收发一体超声波探头的超声波测距方案(附源代码和原理图)
  14. 高通使用/system/bin/r读取msm8916的gpio配置
  15. 在 csproj 文件中使用系统环境变量的值(示例将 dll 生成到 AppData 目录下)
  16. Java项目:SSH公交路线查询网站系统
  17. ibm服务器修复安装win7系统,联想thinkpad无法开机重装win7,教你重装系统攻略
  18. HDU 6578 Blank
  19. 前端利用docker在linux上部署nginx服务
  20. matlab如何提取某一列的数据_MATLAB如何提取某一矩阵的某一列的部分数据?

热门文章

  1. UCP Message Structure
  2. 王道考研计算机网络笔记,王道考研-操作系统整理笔记.pdf
  3. 我眼中的:中国最美的情诗词
  4. 微型光学防抖摄像头模组的自动化生产调试技术
  5. 计算机电源 80plus,电脑的电源要如何选择?80PLUS是什么意思?一定要选全模组吗?...
  6. 2块一瓶,2空瓶换一瓶,4瓶盖换一瓶,10块钱喝几瓶?
  7. 一元二次函数的万能公式
  8. 洛谷P4799:世界冰球锦标赛【折半搜索】
  9. AI与轨交并行,智慧服务伴乘客出行
  10. CodeForces - 29A Spit Problem【水题】