20分WA求助
查看原帖
20分WA求助
1013485
lishengrui318楼主2023/12/19 21:05

如何使内存变少

#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) 
				{
					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;	
}
2023/12/19 21:05
加载中...