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

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

Sample Output

  1. [-5.000,3.000]
  2. [-7.000,6.000]
  3. [2.000,15.000]
  4. [-50.000,5.000]
  5. [0.150,25.000]
  1.  
  2. 【题解】
  3.  
  4. 对于进行的运算。
  5.  
  6. a=[x1,y1],b=[x2,y2]
  7.  
  8. a+b = [x1+x2,y1+y2]
  9.  
  10. a-b = [x1-y2,y1-x2];
  11.  
  12. d1 = x1 m x2,d2 = x1 m y2,d3 = y1 m x2,d4 = y1 m y2;
  13.  
  14. a*b = [min(d1..d4,m=*),max(d1..d4,m=*)];
  15.  
  16. a/b = [min(d1..d4,m=/),max(d1..d4,m=/)];
  17.  
  18. 对于取反。一开始的时候先判断出哪些是取反符号(很容易就能想到要怎么判断的。)
  19.  
  20. 然后在取反符号前加"([0,0]",然后在取反符号后面恰当的位置加上")"。就是把取反运算变成一个减法
  21.  
  22. 运算。
  23.  
  24. 然后利用二分的方法来求表达式。
  25.  
  26. 具体的。
  27.  
  28. 先找到一个表达式里面运算的优先级别最小的运算符。
  29.  
  30. 然后递归这个运算符左边的表达式。递归右边的表达式。
  31.  
  32. 如果当前处理的表达式全为区间。则返回这个区间的端点。存在struct结构体中。
  33.  
  34. 这个递归也是一个struct 结构体。所以可以直接返回。
  35.  
  36. 同一优先级别的操作符。往后找。这样可以保证同一优先级。从左到右运算的顺序。
  37.  
  38. 【代码】
  39. #include <cstdio>
  40. #include <iostream>
  41. #include <stdlib.h>
  42. #include <string>
  43. using namespace std;
  44. struct qujian //结构体。存区间的端点
  45. {
  46. 	double l,r;
  47. };
  48. bool chu0 = false; //用于判断是否除0,因为不能直接结束程序。所以有点麻烦。 
  49. void check(string & s) //把多余的空格去掉
  50. {
  51. 	int l = s.size()-1;
  52. 	for (int i = 1;i <= l;i++)
  53. 		if (s[i] == ' ')
  54. 			s[i] = '$'; //先变成一个标识符
  55. 	string ss = " ";
  56. 	for (int i = 1;i <= l;i++) //然后把那些不是标识符的加到ss这个temp变量上
  57. 		if (s[i]!='$')
  58. 			ss+=s[i];
  59. 	s = ss;	 //最后把temp变量赋值给s ,完成去除空格的任务。
  60. }
  61. bool reducebracket(string &s) //去掉两边的括号,如( (..) + (..))
  62. {//则变成(..)+(..)  注意string 要加& 不然s不会改变
  63. 	int l = s.size()-1; //因为在前面加了一个空格,所以从1开始数起
  64. 	if (s[1] != '(' || s[l] != ')') //如果最左和最右不是配对的括号则不可能
  65. 		return false; //返回不要去括号
  66. 	int b = 0; //因为可能出现(xxx) + (xxx)的情况。(两边是配对的括号,但不要去)
  67. 	for (int i = 2;i <= l-1;i++) //在2到l-1的范围内看括号是否匹配。
  68. 		{
  69. 			if (s[i] == '(')
  70. 				b++;
  71. 			if (s[i] == ')')
  72. 				b--;
  73. 			if (b < 0)
  74. 				return false; //如果不匹配则返回不去除。这可以考虑到上述情况
  75. 		}
  76. 	s = s.erase(l,1); //去掉两边的括号
  77. 	s = s.erase(1,1);
  78. 	return true; //返回可以再尝试去括号
  79. }
  80. char cmp(char x,char y) //比较x操作符和y操作符的优先顺序
  81. {
  82. 	if (x == '&') //如果是初值,则一定更新
  83. 		return '>';
  84. 	if (x == '*' || x == '/') //如果是同一级别的要尽量往后(同一级从左到右)
  85. 		return '>'; //其他的按照小学知识就能知道优先顺序了。
  86. 	if ( (x == '+' || x == '-') && (y == '+' || y == '-'))
  87. 		return '>';  //在找的时候会一层层去掉括号,所以不要管括号
  88. 	return '<';
  89. }
  90. int find (string s) //找s里面运算符级别最小的运算符位置
  91. {
  92. 	char now = '&'; //置初值
  93. 	int l = s.size()-1;
  94. 	int i = 1,k;
  95. 	while (i <= l)
  96. 		{
  97. 			if (s[i] == '(') //如果是括号就要跳过。
  98. 				{
  99. 					int b = 0;
  100. 					do
  101. 					{
  102. 						if (s[i] == '(')
  103. 							b++;
  104. 						if (s[i] == ')')
  105. 							b--;
  106. 						i++; //进行括号的匹配
  107. 					}
  108. 					while (b!=0);
  109. 				}
  110. 				else
  111. 					if ((s[i] == '*' || s[i] == '/' || s[i] == '+')
  112. 							||
  113. 								(s[i] == '-' && i > 1 &&
  114. 									(s[i-1] ==']' || s[i-1] == ')')
  115. 								)) //这一大串都是判断这个是不是操作符
  116. 						{
  117. 							if (cmp(now,s[i]) == '>') //如果这个操作符更小
  118. 								{ //则更新
  119. 									now = s[i];
  120. 									k = i;
  121. 								}
  122. 							i++; //无论如何都要递增i
  123. 						}
  124. 							else
  125. 								i++;
  126. 		}
  127. 	return k;
  128. }
  129. double best_max(double x,double y,double z,double w) //返回几个数中最大的数
  130. {
  131. 	double m = x;
  132. 	if (y > m)
  133. 		m = y;
  134. 	if (z > m)
  135. 		m = z;
  136. 	if (w > m)
  137. 		m = w;
  138. 	return m;
  139. }
  140. double best_min(double x,double y,double z,double w) //返回几个数中最小的数
  141. {
  142. 	double m = x;
  143. 	if (y < m)
  144. 		m = y;
  145. 	if (z < m)
  146. 		m = z;
  147. 	if (w < m)
  148. 		m = w;
  149. 	return m;
  150. }
  151. qujian reduce(string s) //这是递归的主程序
  152. {
  153. 	qujian temp;
  154. 	if (chu0) //如果除0了就随便返回一个结构体。
  155. 		return temp;
  156. 	if (s == " ") //如果为空则返回0 我们之前有加一个空格在头部
  157. 		{
  158. 			temp.l = 0;
  159. 			temp.r = 0;
  160. 			return temp;
  161. 		}
  162. 	bool judge = false; //判断这个字符串有没有操作符
  163. 	int l = s.size()-1;
  164. 	for (int i = 1;i <= l;i++) //如果有操作符就返回true
  165. 		if (s[i] == '*' || s[i] == '/' || s[i] == '+')
  166. 			{
  167. 				judge = true;
  168. 				break;
  169. 			}
  170. 			else //减号的判断要小心出现负数的情况。这会麻烦点。
  171. 				if (s[i] == '-' && i > 1 && (s[i-1] ==']' ||
  172. 						s[i-1] == ')'))
  173. 							{
  174. 								judge = true;
  175. 								break;
  176. 							}
  177. 	if (!judge) //如果没有出现操作符。则这是一个区间
  178. 		{
  179. 			int p1 = s.find('[',0),p2 = s.find(',',0);
  180. 			string s1 = s.substr(p1+1,p2-p1-1);
  181. 			int p3 = s.find(']',0);
  182. 			string s2 = s.substr(p2+1,p3-p2-1); //把这个区间的a,b取出来
  183. 			temp.l = atof(s1.c_str());
  184. 			temp.r = atof(s2.c_str()); //转成double类型
  185. 			if (temp.l > temp.r) //会出现a > b的情况。很恶心。。
  186. 				{
  187. 					double te;
  188. 					te = temp.l;
  189. 					temp.l = temp.r;
  190. 					temp.r = te;
  191. 				}
  192. 			return temp;
  193. 		}
  194. 	bool flag = reducebracket(s); //如果能去除两边多余括号就去除
  195. 	while (flag)
  196. 		flag = reducebracket(s);
  197. 	int k = find(s); //找到运算符的位置。
  198. 	string sl = s.substr(0,k); //截取运算符的左边和右边
  199. 	char key = s[k]; //取出操作符
  200. 	s = s.erase(1,k);//删掉左边,保留空格。所以从1开始
  201. 	string sr = s; //右边就直接等于删掉后剩余的东西
  202. 	qujian temp1 = reduce(sl),temp2= reduce(sr);//递归左边和右边
  203. 	if (chu0) //如果除0了就随便返回个值。(没用的)
  204. 		return temp1;
  205. 	qujian temp3;
  206. 	switch (key) //根据我在题解写的规则进行运算,注意判断除0
  207. 		{
  208. 			case '+':
  209. 				temp.l=temp1.l+temp2.l,temp.r=temp1.r+temp2.r;
  210. 				break;
  211. 			case '-':
  212. 				temp.l=temp1.l-temp2.r,temp.r=temp1.r-temp2.l;
  213. 				break;
  214. 			case '*':
  215. 				{
  216. 					temp.r = best_max(temp1.l*temp2.l,temp1.l*temp2.r,
  217. 									  temp1.r*temp2.l,temp1.r*temp2.r);
  218. 					temp.l = best_min(temp1.l*temp2.l,temp1.l*temp2.r,
  219. 									  temp1.r*temp2.l,temp1.r*temp2.r);
  220. 				}
  221. 				break;
  222. 			case '/':
  223. 				{
  224. 					if (temp2.l <=0 && temp2.r >=0) //如果除0,则退出这层递归。
  225. 						{
  226. 							 chu0 = true; //标记除0信息
  227. 							 return temp2;
  228. 						}
  229. 					temp.r = best_max(temp1.l/temp2.l,temp1.l/temp2.r,
  230. 									  temp1.r/temp2.l,temp1.r/temp2.r);
  231. 					temp.l = best_min(temp1.l/temp2.l,temp1.l/temp2.r,
  232. 									  temp1.r/temp2.l,temp1.r/temp2.r);
  233. 				}
  234. 				break;
  235. 		}
  236. 	return temp;
  237. }
  238. void input_data()
  239. {
  240. 	string ss;
  241. 	while ( getline(cin,ss)) //有多行输入
  242. 		{
  243. 			string s = " +"; //在开头加一个加号。这样可以防止一开始就有取反符
  244. 			s += ss; //加号左边是空。我们会默认返回0
  245. 			check(s); //看看有没有多余的空格
  246. 			chu0 = false; //是否除0要重置
  247. 			int ll = s.size()-1;
  248. 			int i = 1;
  249. 			while (i <= ll-1)
  250. 				{ //这里是取反符的改变方法
  251. 					if (i > 1 && s[i] == '-' && s[i-1]!=']' && (s[i+1] > '9' || s[i+1] <'0'))
  252. 						{ //判断是否为取反符的方法
  253. 							s = s.insert(i,"([0,0]");//把它变成减法
  254. 							i+=6; //i指向'-'
  255. 							i++;
  256. 							int j = i;
  257. 							if (s[i] == '(') //如果后面是括号则要跳过括号内的内容
  258. 								{
  259. 									int b = 0;
  260. 									do
  261. 									{
  262. 										if (s[i] == '(') b++;
  263. 										if (s[i] == ')') b--;
  264. 										i++;
  265. 									}
  266. 									while (b!=0);
  267. 									s = s.insert(i,")");//加一个右括号
  268. 									i = j;//返回之前的位置。因为括号里可能也有取反符
  269. 								}
  270. 							if (s[i] == '[') //如果是个区间。只要到区间右边加括号就好
  271. 								{
  272. 									while (s[i] != ']') i++;
  273. 									i++;
  274. 									s = s.insert(i,")");
  275. 								}
  276. 							ll = s.size();//要重新获取字符长度
  277. 						}
  278. 					i++; //递增指针
  279. 				}
  280. 			qujian l = reduce(s); //获取答案区间
  281. 			if (chu0) //是否除0做出判断
  282. 				printf("Division by zero\n");
  283. 					else
  284. 						printf("[%.3lf,%.3lf]\n",l.l,l.r);	
  285. 		}
  286. }
  287. int main()
  288. {
  289. 	input_data();
  290. 	return 0;
  291. }

【t094】区间运算的更多相关文章

  1. SICP 练习 (2.9)解决摘要:宽度和区间运算的关系间隔

    SICP 2.9 像是一个数学题,要我们证明区间的和与差的宽度是被加和被减的区间的宽度的函数,而对于乘法和除法来说不成立. 书中所谓宽度就是区间起点和终点差的一半.以我看来更像是区间宽度的一半.无论怎 ...

  2. (线段树 区间运算求点)Flowers -- hdu -- 4325

    http://acm.hdu.edu.cn/showproblem.php?pid=4325 Flowers Time Limit: 4000/2000 MS (Java/Others)    Mem ...

  3. 当AS3遇见Swift(一)

    当AS3遇见Swift 从Hello开始 As3 trace(“Hello Eko”) Swift println(“Hello Eko”) 挺象,有点隔壁王叔叔的意思. 常量和变量 As3 publ ...

  4. Spring表达式语言 之 5.3 SpEL语法(拾肆)

    5.3  SpEL语法 5.3.1  基本表达式 一.字面量表达式: SpEL支持的字面量包括:字符串.数字类型(int.long.float.double).布尔类型.null类型. 类型 示例 字 ...

  5. Guava 8-区间

    范例 List scores; Iterable belowMedian =Iterables.filter(scores,Range.lessThan(median)); ... Range val ...

  6. swift3.0基础语法

    swift 3.0 基础语法 目录 01-变量和常量 02-运算符 03-可选项 04-条件语句 05-循环 06-字符串 07-元组 08-数组 09-字典 10-对象和类 11-枚举 12-属性 ...

  7. Asp.Net中的消息处理---MSMQ系列学习(一)

    刚刚毕业一年,比较浮躁,上次面试被问到消息队列,觉得非常的惭愧因为不知道,所以下定决心一定要学会使用它.以前只是听说过有这么个东西,要说是什么,在什么场景下使用却是无从知晓,因为自己也确实没有在项目中 ...

  8. Boost程序库完全开发指南——深入C++“准”标准库(第3版)

    内容简介  · · · · · · Boost 是一个功能强大.构造精巧.跨平台.开源并且完全免费的C++程序库,有着“C++‘准’标准库”的美誉. Boost 由C++标准委员会部分成员所设立的Bo ...

  9. C 语言资源大全中文版

    C 语言资源大全中文版 我想很多程序员应该记得 GitHub 上有一个 Awesome - XXX 系列的资源整理.awesome-c 是 koz.ross 发起维护的 C 语言资源列表,内容包括了: ...

随机推荐

  1. Log4j中为什么设计isDebugEnabled()方法

    转自:https://www.jianshu.com/p/e1eb7ebfb21e 先看下面的代码,在真正执行logger.debug()之前,进行了logger.isDebugEnabled()的判 ...

  2. Java exception handling best practices--转载

    原文地址:http://howtodoinjava.com/2013/04/04/java-exception-handling-best-practices/ This post is anothe ...

  3. python3输出range序列

    b=range(3)         #输出的是[0, 1, 2] ,其实这里如果用在循环上,代表着循环多少次,这里是循环3次.从零开始.print(list(b))

  4. 【习题 3-10 UVA - 1587】Box

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 枚举某个顶角的三个相邻面就好. 看看这三个相邻面有没有对应的面. 以及3个相邻面的6个边. 能否分成2个a,2个b,2个c 也即每个 ...

  5. async和await在项目中的应用

    Async基础知识: async函数是ES7标准引入的语法,基于Generator函数实现的,也就是说是Generator函数的语法糖.什么是Generator函数?(留个坑) 返回值是Promise ...

  6. 【习题 3-6 UVA - 232】Crossword Answers

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 模拟题.注意场宽为3 [代码] #include <bits/stdc++.h> using namespace std ...

  7. 安装hadoop2.6.0伪分布式环境 分类: A1_HADOOP 2015-04-27 18:59 409人阅读 评论(0) 收藏

    集群环境搭建请见:http://blog.csdn.net/jediael_lu/article/details/45145767 一.环境准备 1.安装linux.jdk 2.下载hadoop2.6 ...

  8. localStorage兼容方案

    localStorage是H5的存储方案,各大浏览器支持都相当不错,唯一悲催的就是IE,这个浏览器界的另类总是显得格格不入. IE “Internet选项”->“安全”中有一个“启动保护模式”的 ...

  9. Struts(22)标签库具体解释

    要使用Struts2的标签,仅仅须要在JSP页面加入例如以下一行定义就可以: <%@ taglib prefix="s" uri="/struts-tags&quo ...

  10. Android学习笔记:Home Screen Widgets(2):关于Widget

    通过widget定义,我们在widget列表中看到了我们的TestWidget.当我们拖拽widget到主页时,假设在appwidet-provider中定义了android:configure的ja ...