Codeforces Beta Round #7 E. Defining Macros(二叉表达式树)

185 篇文章 0 订阅

Most C/C++ programmers know about excellent opportunities that preprocessor #define directives give; but many know as well about the problems that can arise because of their careless use.

In this problem we consider the following model of #define constructions (also called macros). Each macro has its name and value. The generic syntax for declaring a macro is the following:

#define macro_name macro_value

After the macro has been declared, "macro_name" is replaced with "macro_value" each time it is met in the program (only the whole tokens can be replaced; i.e. "macro_name" is replaced only when it is surrounded by spaces or other non-alphabetic symbol). A "macro_value" within our model can only be an arithmetic expression consisting of variables, four arithmetic operations, brackets, and also the names of previously declared macros (in this case replacement is performed sequentially). The process of replacing macros with their values is called substitution.

One of the main problems arising while using macros — the situation when as a result of substitution we get an arithmetic expression with the changed order of calculation because of different priorities of the operations.

Let's consider the following example. Say, we declared such a #define construction:

#define sum x + y

and further in the program the expression "2 * sum" is calculated. After macro substitution is performed we get "2 * x + y", instead of intuitively expected "2 * (x + y)".

Let's call the situation "suspicious", if after the macro substitution the order of calculation changes, falling outside the bounds of some macro. Thus, your task is to find out by the given set of #define definitions and the given expression if this expression is suspicious or not.

Let's speak more formally. We should perform an ordinary macros substitution in the given expression. Moreover, we should perform a "safe" macros substitution in the expression, putting in brackets each macro value; after this, guided by arithmetic rules of brackets expansion, we can omit some of the brackets. If there exist a way to get an expression, absolutely coinciding with the expression that is the result of an ordinary substitution (character-by-character, but ignoring spaces), then this expression and the macros system are called correct, otherwise — suspicious.

Note that we consider the "/" operation as the usual mathematical division, not the integer division like in C/C++. That's why, for example, in the expression "a*(b/c)" we can omit brackets to get the expression "a*b/c".


题意:给一堆定义好的宏,然后给你一个表达式,问这个表达式是否安全,如: #define a x+y,那么表达式2*a就是不安全的,因为会被替换成2*x+y.


分析:不合法的情况有那么几种:加号连接的两个式子中优先级最低的运算符为加减号,减号连接的后一个式子中优先级最低的运算符为加减号,除号连接的两个式子中右式子不是一个整体或左式子由加减号连接。那么我们可以通过建立二叉表达式树来获取每个宏的优先级最低运算符,根据表达式记忆化建立表达式树,这道题没必要真的把树给建出来,只需要保留每次合并后剩下根节点的安全级别就行,另外此题数据巨坑无比,#(空格)define 和 n = 0这种数据都有。


#include<iostream>
#include<string>
#include<cstdlib>
#include<cstdio>
#include<set>
#include<map>
#include<vector>
#include<cstring>
#include<stack>
#include<cmath>
#include<queue>
#define INF 0x3f3f3f3f
#define N 210
using namespace std;
int n;
map <string,int> f,f2;
const bool camp[7][7] =
{
	{1,1,0,0,0,1,1},{1,1,0,0,0,1,1},{1,1,1,1,0,1,1},
	{1,1,1,1,0,1,1},{0,0,0,0,0,0,0},{0,0,0,0,0,0,0},
	{0,0,0,0,0,0,0}
};
char st[N],str[101][N];
int idx(char c)
{
	switch(c)
	{
		case '+' : return 0;
		case '-' : return 1;
		case '*' : return 2;
		case '/' : return 3;
		case '(' : return 4;
		case ')' : return 5;
		case '\0' : return 6;
	}
}
void GG()
{
    printf("Suspicious\n");
    exit(0);
}
void oper(stack<char> &s1,stack<int> &s2)
{
	int a = s2.top();
	s2.pop();
	int b = s2.top();
	s2.pop();
	char op = s1.top();
	s1.pop();
	switch (op)
	{
		case '+' : s2.push(2);break;
		case '-' : if(a == 2) GG();s2.push(2);break;
		case '*' : if(a == 2 || b == 2) GG();s2.push(3);break;
		case '/' : if(a != 1 || b == 2) GG();s2.push(3);break;
	}
}
int Build(char st[])
{
    stack <char> s1;
    stack <int> s2;
	int pos = 0;
	while(st[pos] != '\0')
	{
		if((st[pos] >= 'a' && st[pos] <= 'z') || (st[pos] >= '0' && st[pos] <= '9') || (st[pos] >= 'A' && st[pos] <= 'Z'))
		{
            string now = "";
            while((st[pos] >= 'a' && st[pos] <= 'z') || (st[pos] >= '0' && st[pos] <= '9') || (st[pos] >= 'A' && st[pos] <= 'Z'))
            {
                now = now + st[pos]; 
                pos++;
            }
            pos--;
            if(!f2[now])
            {
                if(f[now]) f2[now] = Build(str[f[now]]);
                else f2[now] = 1;
            }
            s2.push(f2[now]);
			while(s1.size() && camp[idx(s1.top())][idx(st[pos+1])]) oper(s1,s2);
		}
		else
		{
		    s1.push(st[pos]);
			if(s1.top() == ')')
			{
                s1.pop();
                s1.pop();
                s2.pop();
                s2.push(1);
                while(s1.size() && camp[idx(s1.top())][idx(st[pos+1])]) oper(s1,s2);
			}
		}
		pos++;
	}
	return s2.top();
}
int main()
{
    scanf("%d",&n);
    if(n == 0)
    {
        printf("OK\n");
        return 0;
    }
    for(int i = 1;i <= n;i++)
    {
        string tem;char temp[200];
        while(cin>>tem && tem != "define\0" && tem != "#define\0");
        scanf("%s",temp);
        tem = temp;
        f[tem] = i;
        cin.getline(str[i],201);
    }
    for(int i = 1;i <= n;i++)
    {
        int k = 0,len = strlen(str[i]);
        for(int j = 0;j <= len;j++)
         if(str[i][j] != ' ') str[i][k++] = str[i][j];
    }
    cin.getline(st,201);
    int k = 0,len = strlen(st);
    for(int j = 0;j <= len;j++)
     if(st[j] != ' ') st[k++] = st[j];
	Build(st);
	printf("OK\n");
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值