【NOIP2011模拟9.15】区间运算——栈解决

来源:互联网 发布:javascript设计模式pdf 编辑:程序博客网 时间:2024/06/15 21:24

【NOIP2011模拟9.15】区间运算

Time Limits: 1000 ms Memory Limits: 131072 KB

Description
区间运算是数学的一个领域。在区间运算中,常量和变量并不表示为一个单独、精确的
数轴上的一个点;而在区间运算中,一个数量表示数轴上的一段,例如[3,5]表示数轴上从3 到5 的一段。当精确的数值表示为区间时,上界与下界是相同的,如5 表示为区间即[5,5]。
两个区间的运算,是指一个区间中的每个点与另一个区间中的每个点所做的运算,通过
运算所得的所有点的集合即为运算的结果。例如,[3,5]+[-10,1]=[-7,6]。你的任务是写一个可以根据单行表达式进行取反数、加、减、乘、除等基本的区间运算的程序。下面是一些运算
的例子:

取相反数-[-3,5]=[-5,3]
加法[3,5]+[-10,1]=[-7,6]
减法[3,5]-[-10,1]=[2,15]
乘法[3,5]*[-10,1]=[-50,5]
除法[3,5]/[-10,-0.1]=[-50,-0.3]

Input
程序的输入包含一行或多行区间运算的中缀表达式,每个区间都表示为[min,max],表
达式中包括括号、负号(-)、加号(+)、减号(-)、乘号(*)和除号(/),括号可能是嵌套的。每一行中都有可能有空格,但空格不会在表示区间的括号“[min,max]”中间或负号后出现。程序不需要处理科学记数法(如2E6=2000000)。每一行均不超过80 个字符。运算采用标准的优先级规则。下面按优先级递减的顺序给出各个运算符:
1. () 括号
2. - 取相反数
3. * / 乘法和除法,同级运算按从左往右的顺序
4. + - 加法和减法,同级运算按从左往右的顺序

Output
对于输入的每一行,都相应地输出一行,输出的内容就是区间运算的最后结果,用
[min,max]的形式表示,其中min 不能大于max,输出结果都精确到小数点后第三位,区间
形式中间不能有空格。但如果表达式里面有除法,而且作为除数的区间包含0,则输出
“Division by zero”即可。

Sample Input

-[-3,5][3,5]+[-10,1][3,5]-[-10,1][3,5]*[-10,1](([3,5]/[-10,-0.1])/-[2,2])

Sample Output

[-5.000,3.000][-7.000,6.000][2.000,15.000][-50.000,5.000][0.150,25.000]

有些朋友都认为,关于字符串中的运算都不怎么好处理,其实是这样的。
对于这道题,让我们当一个简易的计算器,对这样的字符串进行处理也是比较难的。
但是我们还是对症下药,找到了解决这种问题的最优方法——栈,栈的复杂度是十分优良的,空间和时间都基本可以在O(n)上解决。接下来我就介绍这种用栈来解算式问题的方法。

我们先对单纯的算式来讲解。

首先,我们可以在算式的两侧加上括号。

如3+5变成(s+5),(2 * 5+3)/2-1变成((2 * 5+3)/2-1)。
我们就可以发现算式中字符出现的规律:

左括号->负号->数字->运算符号或者右括号

于是我们可以针对这样的顺序进行栈处理。

首先:如果遇到了左括号,就进行压栈处理

while(st[h]=='(')push(),h++;
void push(){    sym[++top]=st[h];}

第二:如果遇到负号,就把它改成‘=’避免与减号弄混,压入栈中

if(st[h]=='-'){    st[h]='=';    push();h++;}

第三:对数字的处理,找出数字的那一串数,转化为数字,放到当前符号对应的位置中

if(st[h]>='0' && st[h]<='9'){    t=h;    while(st[h]>='0' && st[h]<='9')++h;    PutNum(t,h-1);}
void PutNum(int h,int t){    int number=0;    for(int i=h;i<=t;i++)number+=(number<<3)+number+st[i]-'0';    num[top]=number;}

最后:对符号和右括号的处理:
符号,判断优先级:

bool can(){    if((st[h]=='+' || st[h]=='-' || st[h]=='*' || st[h]=='/')&&(sym[top]=='('))return 0;    if(sym[top]=='=')return 1;    if((st[h]=='*' || st[h]=='/')&&(sym[top]=='+' || sym[top]=='-'))return 0;    return 1;}

然后计算:

void pop(){    top--;    if(sym[top+1]=='=')num[top]=-num[top+1];    if(sym[top+1]=='+')num[top]+=num[top+1];    if(sym[top+1]=='-')num[top]-=num[top+1];    if(sym[top+1]=='*')num[top]*=num[top+1];    if(sym[top+1]=='/')    {        if(!num[top+1])        {            printf("Divided By Zero!");            p=1;return;        }        num[top]/=num[top+1];    }}

压栈:

while(can()){    pop();if(p)return 0;}push();

右括号处理,运算,弹栈:

while(st[h]=='(')push(),h++;if(st[h]=='-'){    st[h]='=';    push();h++;    }if(st[h]>='0' && st[h]<='9'){    t=h;    while(st[h]>='0' && st[h]<='9')++h;    PutNum(t,h-1);}

所以,对算式的运算代码如下:

#include<cstdio>#include<cstring>using namespace std;int len,num[100003],top,h,t;char st[100003],sym[100003];bool p=0;int GetLength();void push();void PutNum(int,int);void pop();bool can();int main(){    memset(st,0,sizeof(st));    scanf("%s",st+1);    len=GetLength()+2;    for(int i=len-1;i>=2;i--)st[i]=st[i-1];    st[1]='(';    st[len]=')';    top=0;    h=1;    while(h<len)    {        while(st[h]=='(')push(),h++;        if(st[h]=='-')        {            st[h]='=';            push();h++;        }        if(st[h]>='0' && st[h]<='9')        {            t=h;            while(st[h]>='0' && st[h]<='9')++h;            PutNum(t,h-1);        }        do        {            if(st[h]==')')            {                while(sym[top]!='(')                {                    pop();if(p)return 0;                }                top--;                num[top]=num[top+1];            }else            {                while(can())                {                    pop();if(p)return 0;                }                push();            }            h++;        }while(h<=len && st[h-1]==')');    }    printf("%d",num[0]);} bool can(){    if((st[h]=='+' || st[h]=='-' || st[h]=='*' || st[h]=='/')&&(sym[top]=='('))return 0;    if(sym[top]=='=')return 1;    if((st[h]=='*' || st[h]=='/')&&(sym[top]=='+' || sym[top]=='-'))return 0;    return 1;}void pop(){    top--;    if(sym[top+1]=='=')num[top]=-num[top+1];    if(sym[top+1]=='+')num[top]+=num[top+1];    if(sym[top+1]=='-')num[top]-=num[top+1];    if(sym[top+1]=='*')num[top]*=num[top+1];    if(sym[top+1]=='/')    {        if(!num[top+1])        {            printf("Division By Zero!");            p=1;return;        }        num[top]/=num[top+1];    }}void PutNum(int h,int t){    int number=0;    for(int i=h;i<=t;i++)number+=(number<<3)+number+st[i]-'0';    num[top]=number;}void push(){    sym[++top]=st[h];}int GetLength(){    int ans=0,w=0;    while(st[++w])ans++;    return ans;}

区间运算也是一样,只是一个数换成了一个区间:
注意一下运算方式就可以了。

#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#define max(x,y) ((x)>(y)?(x):(y))#define min(x,y) ((x)<(y)?(x):(y))using namespace std;char st[85],sym[85];double num[85][2];int top,h,t,tot;bool bz;int Getlen();void GetNum(int,int,int);void push();void pop();bool can();int main(){    freopen("algorithm.in","r",stdin);    while(1)    {        memset(st,0,sizeof(st));        memset(sym,0,sizeof(sym));        top=0;        scanf("%s\n",st+1);        int len=Getlen()+2;        for(int i=len-1;i>=2;i--)st[i]=st[i-1];        st[1]='(';        st[len]=')';        if(len==2)break;        bz=1;        h=1;        while(h<=len)        {            if(st[h]=='-')            {                st[h]='=';                push();                h++;            }            while(st[h]=='(')            {                push();                h++;            }            if(st[h]=='-')            {                st[h]='=';                push();                h++;            }            if(st[h]=='[')            {                t=h;                while(st[h]!=']')h++;                for(int i=t+1;i<h;i++)if(st[i]==',')                {                    GetNum(t,i,h);                    if(num[top][0]>num[top][1])                    {                        double x=num[top][0];                        num[top][0]=num[top][1];                        num[top][1]=x;                    }                    break;                }                h++;            }            do            {                if(st[h]==')')                {                    tot++;                    while(sym[top]!='(')                    {                        pop();                        if(!bz)break;                    }                    if(!bz)break;                    num[top-1][1]=num[top][1];                    num[top-1][0]=num[top][0];                    --top;                }else                {                    while(can())                    {                        pop();                        if(!bz)break;                    }                    push();                    if(!bz)break;                }                ++h;            }while(h<=len && st[h-1]==')');            if(!bz)break;        }        if(bz)printf("[%.3lf,%.3lf]\n",num[0][0],num[0][1]);    }}void pop(){    top--;    if(sym[top+1]=='=')    {        num[top][0]=-num[top+1][1];        num[top][1]=-num[top+1][0];    }    if(sym[top+1]=='+')    {        num[top][0]=num[top][0]+num[top+1][0];        num[top][1]=num[top][1]+num[top+1][1];    }    if(sym[top+1]=='-')    {        num[top][0]=num[top][0]-num[top+1][1];        num[top][1]=num[top][1]-num[top+1][0];    }    if(sym[top+1]=='*')    {        double x,y,z,r;        x=num[top][0]*num[top+1][0];        y=num[top][0]*num[top+1][1];        z=num[top][1]*num[top+1][0];        r=num[top][1]*num[top+1][1];        num[top][0]=min(x,min(y,min(z,r)));        num[top][1]=max(x,max(y,max(z,r)));    }    if(sym[top+1]=='/')    {        if(num[top+1][0]<=0 && num[top+1][1]>=0)        {            printf("Division by zero\n");            bz=0;return;        }        double x,y,z,r;        x=num[top][0]/num[top+1][0];        y=num[top][0]/num[top+1][1];        z=num[top][1]/num[top+1][0];        r=num[top][1]/num[top+1][1];        num[top][0]=min(x,min(y,min(z,r)));        num[top][1]=max(x,max(y,max(z,r)));    }}bool can(){    if(sym[top]=='=')return 1;    if((st[h]=='+' || st[h]=='-' || st[h]=='*' || st[h]=='/')&&(sym[top]=='('))return 0;    if((st[h]=='*' || st[h]=='/')&&(sym[top]=='+' || sym[top]=='-'))return 0;    return 1;}void push(){sym[++top]=st[h];}int Getlen(){    int ans=0,w=1;    while(st[w++])++ans;    return ans;}void GetNum(int h,int s,int t){    bool p=0;    double mo=1.0;    num[top][0]=num[top][1]=0.0;    while(++h<s)    {        if(st[h]>='0' && st[h]<='9')        {            if(p)            {                num[top][0]=num[top][0]+(double)(st[h]-'0')*mo;                mo=mo*0.1;            }else            {                num[top][0]=num[top][0]*10.0+(st[h]-'0')*mo;            }        }        if(st[h]=='.')        {            mo=mo*0.1;            p=1;        }        if(st[h]=='-')mo=-mo;    }    p=0;    mo=1.0;    while(++s<t)    {        if(st[s]>='0' && st[s]<='9')        {            if(p)            {                num[top][1]=num[top][1]+(double)(st[s]-'0')*mo;                mo=mo*10.0;            }else            {                num[top][1]=num[top][1]*10.0+(double)((st[s]-'0')*mo);            }        }        if(st[s]=='.')        {            mo/=10.0;            p=1;        }        if(st[s]=='-')mo=-mo;    }   }
1 0
原创粉丝点击