【t094】区间运算
Time Limit: 1 second
Memory Limit: 128 MB
【问题描述】
区间运算是数学的一个领域。在区间运算中,常量和变量并不表示为一个单独、精确的值,而是表示为一个有着上界和下界的区间
或范围。在普通的运算中,一个数量可以表示为数轴上的一个点;而在区间运算中,一个数量表示数轴上的一段,例如[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]
【输入格式】
程序的输入包含一行或多行区间运算的中缀表达式,每个区间都表示为[min,max],表 达式中包括括号、负号(-)、加号(+)、减号
(-)、乘号(*)和除号(/),括号可能是嵌套的。每一行中都有可能有空格,但空格不会在表示区间的括号“[min,max]”中间或
负号后出现。程序不需要处理科学记数法(如2E6=2000000)。每一行均不超过 80 个字符。运算采用标准的优先级规则。下面按
优先级递减的顺序给出各个运算符:
() 括号
- 取相反数
* / 乘法和除法,同级运算按从左往右的顺序
+ - 加法和减法,同级运算按从左往右的顺序
【输出格式】
对于输入的每一行,都相应地输出一行,输出的内容就是区间运算的最后结果,用[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]
【题解】 对于进行的运算。 设a=[x1,y1],b=[x2,y2] a+b = [x1+x2,y1+y2] a-b = [x1-y2,y1-x2]; d1 = x1 m x2,d2 = x1 m y2,d3 = y1 m x2,d4 = y1 m y2; a*b = [min(d1..d4,m=*),max(d1..d4,m=*)]; a/b = [min(d1..d4,m=/),max(d1..d4,m=/)]; 对于取反。一开始的时候先判断出哪些是取反符号(很容易就能想到要怎么判断的。) 然后在取反符号前加"([0,0]",然后在取反符号后面恰当的位置加上")"。就是把取反运算变成一个减法 运算。 然后利用二分的方法来求表达式。 具体的。 先找到一个表达式里面运算的优先级别最小的运算符。 然后递归这个运算符左边的表达式。递归右边的表达式。 如果当前处理的表达式全为区间。则返回这个区间的端点。存在struct结构体中。 这个递归也是一个struct 结构体。所以可以直接返回。 同一优先级别的操作符。往后找。这样可以保证同一优先级。从左到右运算的顺序。 【代码】#include <cstdio>
#include <iostream>
#include <stdlib.h>
#include <string> using namespace std; struct qujian //结构体。存区间的端点
{
double l,r;
}; bool chu0 = false; //用于判断是否除0,因为不能直接结束程序。所以有点麻烦。 void check(string & s) //把多余的空格去掉
{
int l = s.size()-1;
for (int i = 1;i <= l;i++)
if (s[i] == ' ')
s[i] = '$'; //先变成一个标识符
string ss = " ";
for (int i = 1;i <= l;i++) //然后把那些不是标识符的加到ss这个temp变量上
if (s[i]!='$')
ss+=s[i];
s = ss; //最后把temp变量赋值给s ,完成去除空格的任务。
} bool reducebracket(string &s) //去掉两边的括号,如( (..) + (..))
{//则变成(..)+(..) 注意string 要加& 不然s不会改变
int l = s.size()-1; //因为在前面加了一个空格,所以从1开始数起
if (s[1] != '(' || s[l] != ')') //如果最左和最右不是配对的括号则不可能
return false; //返回不要去括号
int b = 0; //因为可能出现(xxx) + (xxx)的情况。(两边是配对的括号,但不要去)
for (int i = 2;i <= l-1;i++) //在2到l-1的范围内看括号是否匹配。
{
if (s[i] == '(')
b++;
if (s[i] == ')')
b--;
if (b < 0)
return false; //如果不匹配则返回不去除。这可以考虑到上述情况
}
s = s.erase(l,1); //去掉两边的括号
s = s.erase(1,1);
return true; //返回可以再尝试去括号
} char cmp(char x,char y) //比较x操作符和y操作符的优先顺序
{
if (x == '&') //如果是初值,则一定更新
return '>';
if (x == '*' || x == '/') //如果是同一级别的要尽量往后(同一级从左到右)
return '>'; //其他的按照小学知识就能知道优先顺序了。
if ( (x == '+' || x == '-') && (y == '+' || y == '-'))
return '>'; //在找的时候会一层层去掉括号,所以不要管括号
return '<';
} int find (string s) //找s里面运算符级别最小的运算符位置
{
char now = '&'; //置初值
int l = s.size()-1;
int i = 1,k;
while (i <= l)
{
if (s[i] == '(') //如果是括号就要跳过。
{
int b = 0;
do
{
if (s[i] == '(')
b++;
if (s[i] == ')')
b--;
i++; //进行括号的匹配
}
while (b!=0);
}
else
if ((s[i] == '*' || s[i] == '/' || s[i] == '+')
||
(s[i] == '-' && i > 1 &&
(s[i-1] ==']' || s[i-1] == ')')
)) //这一大串都是判断这个是不是操作符
{
if (cmp(now,s[i]) == '>') //如果这个操作符更小
{ //则更新
now = s[i];
k = i;
}
i++; //无论如何都要递增i
}
else
i++;
}
return k;
} double best_max(double x,double y,double z,double w) //返回几个数中最大的数
{
double m = x;
if (y > m)
m = y;
if (z > m)
m = z;
if (w > m)
m = w;
return m;
} double best_min(double x,double y,double z,double w) //返回几个数中最小的数
{
double m = x;
if (y < m)
m = y;
if (z < m)
m = z;
if (w < m)
m = w;
return m;
} qujian reduce(string s) //这是递归的主程序
{
qujian temp;
if (chu0) //如果除0了就随便返回一个结构体。
return temp;
if (s == " ") //如果为空则返回0 我们之前有加一个空格在头部
{
temp.l = 0;
temp.r = 0;
return temp;
}
bool judge = false; //判断这个字符串有没有操作符
int l = s.size()-1;
for (int i = 1;i <= l;i++) //如果有操作符就返回true
if (s[i] == '*' || s[i] == '/' || s[i] == '+')
{
judge = true;
break;
}
else //减号的判断要小心出现负数的情况。这会麻烦点。
if (s[i] == '-' && i > 1 && (s[i-1] ==']' ||
s[i-1] == ')'))
{
judge = true;
break;
}
if (!judge) //如果没有出现操作符。则这是一个区间
{
int p1 = s.find('[',0),p2 = s.find(',',0);
string s1 = s.substr(p1+1,p2-p1-1);
int p3 = s.find(']',0);
string s2 = s.substr(p2+1,p3-p2-1); //把这个区间的a,b取出来
temp.l = atof(s1.c_str());
temp.r = atof(s2.c_str()); //转成double类型
if (temp.l > temp.r) //会出现a > b的情况。很恶心。。
{
double te;
te = temp.l;
temp.l = temp.r;
temp.r = te;
}
return temp;
}
bool flag = reducebracket(s); //如果能去除两边多余括号就去除
while (flag)
flag = reducebracket(s);
int k = find(s); //找到运算符的位置。
string sl = s.substr(0,k); //截取运算符的左边和右边
char key = s[k]; //取出操作符
s = s.erase(1,k);//删掉左边,保留空格。所以从1开始
string sr = s; //右边就直接等于删掉后剩余的东西
qujian temp1 = reduce(sl),temp2= reduce(sr);//递归左边和右边
if (chu0) //如果除0了就随便返回个值。(没用的)
return temp1;
qujian temp3;
switch (key) //根据我在题解写的规则进行运算,注意判断除0
{
case '+':
temp.l=temp1.l+temp2.l,temp.r=temp1.r+temp2.r;
break;
case '-':
temp.l=temp1.l-temp2.r,temp.r=temp1.r-temp2.l;
break;
case '*':
{
temp.r = best_max(temp1.l*temp2.l,temp1.l*temp2.r,
temp1.r*temp2.l,temp1.r*temp2.r);
temp.l = best_min(temp1.l*temp2.l,temp1.l*temp2.r,
temp1.r*temp2.l,temp1.r*temp2.r);
}
break;
case '/':
{
if (temp2.l <=0 && temp2.r >=0) //如果除0,则退出这层递归。
{
chu0 = true; //标记除0信息
return temp2;
}
temp.r = best_max(temp1.l/temp2.l,temp1.l/temp2.r,
temp1.r/temp2.l,temp1.r/temp2.r);
temp.l = best_min(temp1.l/temp2.l,temp1.l/temp2.r,
temp1.r/temp2.l,temp1.r/temp2.r);
}
break;
}
return temp;
} void input_data()
{
string ss;
while ( getline(cin,ss)) //有多行输入
{
string s = " +"; //在开头加一个加号。这样可以防止一开始就有取反符
s += ss; //加号左边是空。我们会默认返回0
check(s); //看看有没有多余的空格
chu0 = false; //是否除0要重置
int ll = s.size()-1;
int i = 1;
while (i <= ll-1)
{ //这里是取反符的改变方法
if (i > 1 && s[i] == '-' && s[i-1]!=']' && (s[i+1] > '9' || s[i+1] <'0'))
{ //判断是否为取反符的方法
s = s.insert(i,"([0,0]");//把它变成减法
i+=6; //i指向'-'
i++;
int j = i;
if (s[i] == '(') //如果后面是括号则要跳过括号内的内容
{
int b = 0;
do
{
if (s[i] == '(') b++;
if (s[i] == ')') b--;
i++;
}
while (b!=0);
s = s.insert(i,")");//加一个右括号
i = j;//返回之前的位置。因为括号里可能也有取反符
}
if (s[i] == '[') //如果是个区间。只要到区间右边加括号就好
{
while (s[i] != ']') i++;
i++;
s = s.insert(i,")");
} ll = s.size();//要重新获取字符长度
}
i++; //递增指针
}
qujian l = reduce(s); //获取答案区间
if (chu0) //是否除0做出判断
printf("Division by zero\n");
else
printf("[%.3lf,%.3lf]\n",l.l,l.r); }
} int main()
{
input_data();
return 0;
}
【t094】区间运算的更多相关文章
- SICP 练习 (2.9)解决摘要:宽度和区间运算的关系间隔
SICP 2.9 像是一个数学题,要我们证明区间的和与差的宽度是被加和被减的区间的宽度的函数,而对于乘法和除法来说不成立. 书中所谓宽度就是区间起点和终点差的一半.以我看来更像是区间宽度的一半.无论怎 ...
- (线段树 区间运算求点)Flowers -- hdu -- 4325
http://acm.hdu.edu.cn/showproblem.php?pid=4325 Flowers Time Limit: 4000/2000 MS (Java/Others) Mem ...
- 当AS3遇见Swift(一)
当AS3遇见Swift 从Hello开始 As3 trace(“Hello Eko”) Swift println(“Hello Eko”) 挺象,有点隔壁王叔叔的意思. 常量和变量 As3 publ ...
- Spring表达式语言 之 5.3 SpEL语法(拾肆)
5.3 SpEL语法 5.3.1 基本表达式 一.字面量表达式: SpEL支持的字面量包括:字符串.数字类型(int.long.float.double).布尔类型.null类型. 类型 示例 字 ...
- Guava 8-区间
范例 List scores; Iterable belowMedian =Iterables.filter(scores,Range.lessThan(median)); ... Range val ...
- swift3.0基础语法
swift 3.0 基础语法 目录 01-变量和常量 02-运算符 03-可选项 04-条件语句 05-循环 06-字符串 07-元组 08-数组 09-字典 10-对象和类 11-枚举 12-属性 ...
- Asp.Net中的消息处理---MSMQ系列学习(一)
刚刚毕业一年,比较浮躁,上次面试被问到消息队列,觉得非常的惭愧因为不知道,所以下定决心一定要学会使用它.以前只是听说过有这么个东西,要说是什么,在什么场景下使用却是无从知晓,因为自己也确实没有在项目中 ...
- Boost程序库完全开发指南——深入C++“准”标准库(第3版)
内容简介 · · · · · · Boost 是一个功能强大.构造精巧.跨平台.开源并且完全免费的C++程序库,有着“C++‘准’标准库”的美誉. Boost 由C++标准委员会部分成员所设立的Bo ...
- C 语言资源大全中文版
C 语言资源大全中文版 我想很多程序员应该记得 GitHub 上有一个 Awesome - XXX 系列的资源整理.awesome-c 是 koz.ross 发起维护的 C 语言资源列表,内容包括了: ...
随机推荐
- 105.UDP通信实现广播
客户端 #include <stdio.h> #include <string.h> #include <winsock.h> #pragma comment(li ...
- 1.1 Introduction中 Kafka for Stream Processing官网剖析(博主推荐)
不多说,直接上干货! 一切来源于官网 http://kafka.apache.org/documentation/ Kafka for Stream Processing kafka的流处理 It i ...
- vue-cli打包项目后,可以修改配置文件
问题: 前端需要修改后台服务器地址url,写好的配置文件会在npm run build 后压缩在一起,传到运行的前端服务器上后,需要到前端打包的源码,找到url地址进行修改.如果不在打包的源码修改,则 ...
- Docker---(7)Docker安装启动RabbitMQ
原文:Docker---(7)Docker安装启动RabbitMQ 版权声明:欢迎转载,请标明出处,如有问题,欢迎指正!谢谢!微信:w1186355422 https://blog.csdn.net/ ...
- jfreechart,pdf生成组件iText,jasper report报表组件及POI操作excel等在企业软件开发中常遇到的第三方应用
熟悉WEB Service ,Ajax,DWR,JQuery,iBatis等技术,熟练TOMCAT,IIS,JBoss,WebLogic等服务器 图表组件JFreeChart PDF组件-iText的 ...
- Android实践 -- Android蓝牙设置连接
使用Android Bluetooth APIs将设备通过蓝牙连接并通信,设置蓝牙,查找蓝牙设备,配对蓝牙设备 连接并传输数据,以下是Android系统提供的蓝牙相关的类和接口 BluetoothAd ...
- mysql 表的timestamp为自动添加
新设计表时可以执行语句: `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP C ...
- stm32的dma缓冲区长度,,存放数据数组会不会冲掉
- css选择器.md
css选择器总结 1.元素选择器 如:*{},body{},p{} ; xml中note{},to{},from{} 2.class与id选择器 如:.class{},#id{} 3.伪类选择器 选择 ...
- u-boot-2011.06在基于s3c2440开发板的移植之引导内核与加载根文件系统
http://www.linuxidc.com/Linux/2012-09/70510.htm 来源:Linux社区 作者:赵春江 uboot最主要的功能就是能够引导内核启动.本文就介绍如何实现该 ...