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
ans[i][0],ans[i][2],ans[i][4]这三个位置都需要尽量出现A或B即使A或B不是最早出现的变量
要求符合这种条件的代码,可以试试以下样例
2
E=C+D
A=C+D
--------
A=C+D//正确输出 ,错误输出是什么都没有
3
E=C+D
A=C+D
B=A+C
-------------
A=C+D
B=A+C//正确输出
/*
E=C+D 错误输出
B=E+C
*/
AC的代码如下
#include <stdio.h>
#include <iostream>
#include <vector>
#include <memory.h>
using namespace std;
string s[110];
int n;
struct node//DAG图中的节点
{
int l = -1;//左孩子
int r = -1;//右孩子
char id;
vector<char>val;//节点值
} t[101];
int num = 0; //序号
int use(int x, char ch)//是否被使用过即在附加标记中出现
{
int len = t[x].val.size();
for(int i = 0; i< len; i++)
{
if(t[x].val[i] == ch)
return 1;
}
return 0;
}
int add_node(char ch)//增加DAG图中的节点并返回序号
{
for(int i = num - 1; i >= 0; i--)//倒着来,为了找在当前步骤前最后改动的
{
if(t[i].id == ch || use(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++;
return;
}
int flag[101];//标记当前序号下是否输出
char ans[1010][1010];//输出的表达式存在这里
void dfs(int x)
{
if(t[x].l != -1 && t[x].r != -1)
{
flag[x] = 1;
dfs(t[x].l);
dfs(t[x].r);
}
}
int main()
{
cin>>n;
memset(flag, 0, sizeof(flag));
for(int i = 0; i < n; i++)
{
cin>>s[i];
int l = add_node(s[i][2]);//记录左右儿子的序号
int r = add_node(s[i][4]);
add_op(s[i][3], s[i][0], l, r);//生成
}
/*找出内部节点即能生成表达式的节点
内部节点是左右叶子为空
*/
//ans[i][0],ans[i][2],ans[i][4]这三个位置都需要尽量出现A或B即使A或B不是最早出现的变量
for(int i = 0; i < num; i++)
{
if(t[i].l!=-1&&t[i].r!=-1)
{
int f=0;
for(int j=0;j<t[i].val.size();j++)
{
if(t[i].val[j]=='A') f=1;
if(t[i].val[j]=='B') f=2;
}
if(f==1) ans[i][0]='A';
else if(f==2) ans[i][0]='B';
else ans[i][0]=t[i].val[0];
ans[i][1]='=';
int l=t[i].l;
int r=t[i].r;
/*左枝*/
if(t[l].val.size()>0)
{
f=0;
for(int j=0;j<t[l].val.size();j++)
{
if(t[l].val[j]=='A') f=1;
if(t[l].val[j]=='B') f=2;
}
if(f==1) ans[i][2]='A';
else if(f==2) ans[i][2]='B';
else ans[i][2]=t[l].val[0];
}
else ans[i][2]=t[l].id;
/*右枝*/
if(t[r].val.size()>0)
{
f=0;
for(int j=0;j<t[r].val.size();j++)
{
if(t[r].val[j]=='A') f=1;
if(t[r].val[j]=='B') f=2;
}
if(f==1) ans[i][4]='A';
else if(f==2) ans[i][4]='B';
else ans[i][4]=t[r].val[0];
}
else ans[i][4]=t[r].id;
ans[i][3]=t[i].id;
ans[i][5]='\0';
}
}
/*由题意只需保留AB,就只将表达式左边有A或B的式子输出
以下就是在寻找式子左端为A,B的表达式,并将表达式中用到的两个因子输出
如果两个因子是经过其他表达式产生的
*/
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])
printf("%s\n", ans[i]);
}
return 0;
}
//用flag[i]标记的方法,而不是直接输出是因为:顺序和避免重复输出
简化版:(提取了个函数)
#include <stdio.h>
#include <iostream>
#include <vector>
using namespace std;
struct node
{
int l=-1,r=-1;
char id;
vector<char> val;
}p[1001];
int num;
bool use(int t,char ch)
{
for(int i=0;i<p[t].val.size();i++)
{
if(p[t].val[i]==ch) return true;
}
return false;
}
int add_node(char ch)
{
for(int i=0;i<num;i++)
{
if(p[i].id==ch||use(i,ch))
{
p[i].val.push_back(ch);
return i;
}
}
p[num].id=ch;
return num++;
}
void add_op(char op,int l,int r,char ch)
{
for(int i=0;i<num;i++)
{
if(p[i].id==op&&p[i].l==l&&p[i].r==r)
{
p[i].val.push_back(ch);return ;
}
}
p[num].id=op;
p[num].l=l;p[num].r=r;
p[num++].val.push_back(ch);
}
int flag[1001];
void dfs(int t)
{
if(p[t].l!=-1||p[t].r!=-1)
{
flag[t]=1;
dfs(p[t].l);
dfs(p[t].r);
}
}
char fun(node t)
{
for(int i=0;i<t.val.size();i++)
{
if(t.val[i]=='A') return 'A';
if(t.val[i]=='B') return 'B';
}
return t.val[0];
}
int main()
{
int n;
cin>>n;char s[101][101];
for(int i=0;i<n;i++)
{
cin>>s[i];
int l=add_node(s[i][2]);
int r=add_node(s[i][4]);
add_op(s[i][3],l,r,s[i][0]);
}
char ans[101][101];
for(int i=0;i<num;i++)
{
if(p[i].l!=-1&&p[i].r!=-1)
{
ans[i][0]=fun(p[i]);
ans[i][1]='=';
int l=p[i].l;
int r=p[i].r;
ans[i][2]=p[l].val.size()>0?fun(p[l]):p[l].id;
ans[i][4]=p[r].val.size()>0?fun(p[r]):p[r].id;
ans[i][3]=p[i].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;
}
return 0;
}