前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >N - DAG优化【编译原理】

N - DAG优化【编译原理】

作者头像
Lokinli
发布2023-03-09 13:34:46
3550
发布2023-03-09 13:34:46
举报
文章被收录于专栏:以终为始

N - DAG优化

Description

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

Input

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

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

例如:A=B+C

Output

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

PS:保证AB的值不同

Sample

Input 

代码语言:javascript
复制
3
A=B+C
B=B+B
A=C+C

Output 

代码语言:javascript
复制
B=B+B
A=C+C
代码语言:javascript
复制
#include <bits/stdc++.h>

using namespace std;
int cnt,n; // cnt 为当前结点的个数,n为输入的表达式个数
char s[10]; //临时输入
char ans[101][101]; // 最后输出的优化后的表达式
bool flas[101]; //用于记录那些表达式最后可以输出

struct st{
    char id; // 结点的值
    int left = -1; // left 和 right 都是存放的标号,即左/右子树所在的标号
    int right = -1;
    vector<char>var;
}node[101];

// i 是第i个结点,c是当前查找的符号
bool find_var(int i, char c)
{
    // 一个结点可能有多个标记
    int len = node[i].var.size();
    for(int k = 0; k < len; k ++)
    {
        if(node[i].var[k] == c)
        {
            // 找到
            return true;
        }
    }
    return false;
}
// 建立结点
// add_node 返回的值时该结点的标号,也就是位置
int add_node(char c)
{
    // 遍历当前已经建立的结点
    for(int i = cnt - 1; i >= 0; i --)
    {
        // 如果该结点建立过,或者和其他结点在同一个上面
        // 这个时候已经变量就会得到合并
        if(node[i].id == c || find_var(i,c))
        {
            return i;
        }
    }
    // 没有找到该结点,则需要新建立
    node[cnt].id = c;
    return cnt ++;
}

//添加表达式
void add_operator(char c, char op, int l, int r)
{
    for(int i = cnt - 1; i >= 0; i --)
    {
        //如果该表达式已经存在,将该表达式左边的值放到结点的var中即可。
        if(op == node[i].id && node[i].left == l && node[i].right == r)
        {
            node[i].var.push_back(c);
            return ;
        }
    }
    // 如果没有,则需要把整个表达式都加进去
    // 形状是结点为操作符,左右结点为操作数,结果存到父节点的var中
    node[cnt].id = op;
    node[cnt].left = l;
    node[cnt].right = r;
    node[cnt].var.push_back(c);
    cnt ++;
}
// 保留变量标记
void dfs(int i){
    // 如果保留的变量需要使用该表达式,则标记为1,保留下来
    if(node[i].left != -1)
    {
        flas[i] = 1;
        dfs(node[i].left);
        dfs(node[i].right);
    }
}
// ok函数
char ok(int i)
{
    int len = node[i].var.size();
    for(int k = 0; k < len; k++)
    {
        // 遍历i结点这个地方是不是有A||B,如果有的话,就说明这个值就没用了,用A||B就行
        if(node[i].var[k] == 'A' || node[i].var[k] == 'B')
        {
            return node[i].var[k];
        }
    }
    // 如果没有那就暂时保存这个值
    return node[i].var[0];
}
int main()
{
    cnt = 0;
    cin >> n;
    for(int i = 0; i < n; i ++)
    {
        cin >> s;
        // 使用add_node建立结点
        int l = add_node(s[2]);
        int r = add_node(s[4]);
        // 将表达式构成树
        // 左右的l、r 使用的就是两个变量存在的标号
        add_operator(s[0],s[3],l,r);
    }
    for(int i = 0; i < cnt; i ++)
    {
        // 保留有左子树的,有左子树情况就是一个表达式的表示
        if(node[i].left != -1){
            // 搞定复写的另一种,比如c = d + d,a = d + d,b = e + c
            // 这时候确定存在ans[i][0]的是a,而不是c
            ans[i][0] = ok(i);
            ans[i][1] = '=';
            // node[i] 是由其左右结点运算得来的
            st ll = node[node[i].left];
            st rr = node[node[i].right];
            // 如果这个结点的左子树不是空的,那操作数就是ok(node[i].left)
            //就是判断c = d + d,a = d + d,b = e + c是否将c换成a
            // 如果是空的,那就是左子树本身的值,即ll.id
            ans[i][2] = ll.left != -1 ? ok(node[i].left) : ll.id;
            ans[i][3] = node[i].id;
            ans[i][4] = rr.left != -1 ? ok(node[i].right) : rr.id;
            ans[i][5] = '\0';
        }
    }
    // 保留所需要变量
    // 题目中要求保留A、B
    for(int i = cnt - 1; i >= 0; i --)
    {
        // 把A能用的表达式或者值进行标记
        if(ans[i][0] == 'A')
        {
            dfs(i);
            break;
        }
    }
     for(int i = cnt - 1; i >= 0; i --)
    {
        // 把B能用的表达式或者值进行标记
        if(ans[i][0] == 'B')
        {
            dfs(i);
            break;
        }
    }
    for(int i = 0; i < cnt; i ++)
    {
        if(flas[i])
        {
            puts(ans[i]);
        }
    }
    return 0;
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-12-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • N - DAG优化
    • Description
      • Input
        • Output
          • Sample
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档