【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; } }
- 【NOIP2011模拟9.15】区间运算——栈解决
- 【NOIP2011模拟9.15】区间运算
- {题解}[jzoj2563]【NOIP2011模拟9.15】区间运算
- 【NOIP2011模拟9.7】雾雨魔理沙
- 【NOIP2011模拟9.7】射命丸文
- 【NOIP2011模拟9.17】旅行
- 【NOIP2011模拟9.20】序列
- 【NOIP2011】【模拟】铺地毯
- 【NOIP2011普及组T4】表达式的值-模拟+栈
- noip2011 数字反转 (模拟)
- 【NOIP2011模拟9.20】素数密度
- NOIP2011模拟9.17 电话时间
- 【NOIP2011模拟9.17】地铁建设
- 【NOIP2011模拟9.9】单词分类
- 【NOIP2011模拟9.9】过河问题
- 【NOIP2011模拟9.9】最短路
- 【NOIP2011模拟9.20】素数密度
- 【NOIP2011模拟9.20】统计方案
- c++ 很隐蔽的指针访问越界的情况---在强制类型转换中发生
- MySQL中的行级锁SELECT FOR UPDATE 和LOCK IN SHARE MODE 区别
- 第一行代码
- OC Block,ARC,GCD
- Redis环境搭建以及简单使用
- 【NOIP2011模拟9.15】区间运算——栈解决
- 数据结构实验:连通分量个数(搬运)
- hdu4027Can you answer these queries?(线段树)
- kmalloc内存申请标志及应用场景
- POJ3126——Prime Path
- java算法4 直接排序
- 基于Swoole的异步消息发送(短信、邮件等)PHP Yaf
- jzoj 4711. 【NOIP2016提高A组模拟8.17】Binary 树状数组+位运算
- vagrant 协作开发工作笔记(一)