#define is unsafe

来源:互联网 发布:朱元璋北伐 知乎 编辑:程序博客网 时间:2024/06/05 11:19
Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other)
Total Submission(s) : 10   Accepted Submission(s) : 8
Problem Description
Have you used #define in C/C++ code like the code below?

#include <stdio.h>
#define MAX(a , b) ((a) > (b) ? (a) : (b))
int main()
{
  printf("%d\n" , MAX(2 + 3 , 4));
  return 0;
}

Run the code and get an output: 5, right?
You may think it is equal to this code:

#include <stdio.h>
int max(a , b) {  return ((a) > (b) ? (a) : (b));  }
int main()
{
  printf("%d\n" , max(2 + 3 , 4));
  return 0;
}

But they aren't.Though they do produce the same anwser , they work in two different ways.
The first code, just replace the MAX(2 + 3 , 4) with ((2 + 3) > (4) ? (2 + 3) : 4), which calculates (2 + 3) twice.
While the second calculates (2 + 3) first, and send the value (5 , 4) to function max(a , b) , which calculates (2 + 3) only once.

What about MAX( MAX(1+2,2) , 3 ) ? 
Remember "replace".
First replace: MAX( (1 + 2) > 2 ? (1 + 2) : 2 , 3)
Second replace: ( ( ( 1 + 2 ) > 2 ? ( 1 + 2 ) : 2 ) > 3 ? ( ( 1 + 2 ) > 2 ? ( 1 + 2 ) : 2 ) : 3).
The code may calculate the same expression many times like ( 1 + 2 ) above.
So #define isn't good.In this problem,I'll give you some strings, tell me the result and how many additions(加法) are computed.
 
Input
The first line is an integer T(T<=40) indicating case number. The next T lines each has a string(no longer than 1000), with MAX(a,b), digits, '+' only(Yes, there're no other characters). In MAX(a,b), a and b may be a string with MAX(c,d), digits, '+'.See the sample and things will be clearer.

Output
For each case, output two integers in a line separated by a single space.Integers in output won't exceed 1000000.
 
Sample Input
6MAX(1,0)1+MAX(1,0)MAX(2+1,3)MAX(4,2+2)MAX(1+1,2)+MAX(2,3)MAX(MAX(1+2,3),MAX(4+5+6,MAX(7+8,9)))+MAX(10,MAX(MAX(11,12),13))

Sample Output
1 02 13 14 25 228 14
 
           这是一道表达式求值问题,模拟题。题目意思就是MAX计算加法的次数其实是比较时进行了一次,返回时又进行了一次。例如:MAX(3+2,4)其实是进行了两次加法。 
    解题思路:
    表达式求值要用到数据结构中的中缀转后缀计算表达式。这就要借助栈来将中缀转为后缀表达式。然后在计算加法的次数即可。本题的关键就在于表达式的中缀转后缀。


代码:
#include <iostream>#include <cstdio>#include <algorithm>#include <stack>#include <cstring>#include <sstream>using namespace std;string S1,S2;///S1为中缀表达式,S2为中缀转化为后缀的表达式struct Num{    int numb;    int time;};int change(double d)///计算各位数字之和{    int sum=0;    ostringstream o;    string c;    if(o<<d)        c=o.str();    for(int i=0;i<c.size();i++)    {        if(c[i]>='0'&&c[i]<='9')            sum+=c[i]-'0';    }    return sum;}/**代码的核心就是定义各个运算符的优先级,通过优先级来将其中缀表达式转化为后缀表达式,进行运算。**/int level(char a)///定义运算符的优先级{    int flag;    switch(a)    {        case ',':flag=1;break;        case 'S':flag=4;break;        case 'M':flag=4;break;        case '+':flag=2;break;        case '-':flag=2;break;        case '*':flag=3;break;        case '/':flag=3;break;        default :flag=0;    }    return flag;}void conversion()///中缀转后缀{    stack<char>Q;    char a;    a='#';    Q.push(a);    int i=0,m=S1.length();    while(i<m)    {        a=Q.top();        if(S1[i]=='(')        {            Q.push(S1[i]);i++;        }        else if(S1[i]==')')        {            while(a!='(')            {                S2=S2+a+'#';Q.pop();a=Q.top();            }            Q.pop();i++;        }        else if(S1[i]=='+'||S1[i]=='-'||S1[i]=='*'||S1[i]=='/'||S1[i]=='S'||S1[i]=='M'||S1[i]==',')        {            while(level(a)>=level(S1[i]))            {                S2=S2+a+'#';Q.pop();a=Q.top();            }            if(S1[i]=='S')            {                Q.push(S1[i]);i+=4;            }            else if(S1[i]=='M')            {                Q.push(S1[i]);i+=3;            }            else if(S1[i]==',')            {                i++;            }            else            {                Q.push(S1[i]);i++;            }        }        else        {            while((S1[i]>='0'&&S1[i]<='9')||S1[i]=='.')            {                S2=S2+S1[i];i++;            }            S2+='#';        }    }    while(!Q.empty())    {        a=Q.top();        Q.pop();        if(a!='#')        {            S2=S2+a+'#';        }    }   // cout<<S2<<endl;///查看中缀转后缀的结果}void calculate()///后缀进行值运算{    int m=S2.length();    int i=0;    Num a,b,N;    stack<Num>W;    int num=0,num1=1;    while(i<m)    {        switch(S2[i])///计算以后将得到的结果入栈        {            case '+':                {                    a=W.top();W.pop();                    b=W.top();W.pop();                    a.numb=a.numb+b.numb;                    a.time=a.time+b.time+1;                    W.push(a);                    i++;break;                }            case 'M':                {                    a=W.top();W.pop();                    b=W.top();W.pop();                    if(a.numb>=b.numb)                    {                        a.time=a.time*2+b.time;                        W.push(a);                        i++;break;                    }                    else                    {                        b.time=b.time*2+a.time;                        W.push(b);                        i++;break;                    }                }            default:///对数字进行处理            {                if(S2[i]>='0'&&S2[i]<='9'&&num1==1)                {                    num=num*10+S2[i]-'0';                    if((S2[i+1]<'0')||(S2[i+1]>'9'))                    {                        N.numb=num;                        N.time=0;                        W.push(N);                    }                }                else                {                    num1=1;                    num=0;                }                i++;            }        }    }    printf("%d %d\n",W.top().numb,W.top().time);///按题目要求定义输出格式}int main(){    int T;    scanf("%d",&T);    while(T--)    {        cin>>S1;        S2="";        conversion();        calculate();    }    return 0;}


  
3 0