POJ1400——Complicated Expressions

问题描述:
Complicated Expressions
Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 1503 Accepted: 485
Description
 
The most important activity of ACM is the GSM network. As the mobile phone operator, ACM must build its own transmitting stations. It is very important to compute the exact behaviour of electro-magnetic waves. Unfortunately, prediction of electro-magnetic fields is a very complex task and the formulas describing them are very long and hard-to-read. For example, below are the Maxwell's Equations describing the basic laws of electrical engineering. 
 
 
ACM has designed its own computer system that can make some field computations and produce results in the form of mathematic expressions. Unfortunately, by generating the expression in several steps, there are always some unneeded parentheses inside the expression. Your task is to take these partial results and make them "nice" by removing all unnecessary parentheses. 
 
Input
 
There is a single positive integer T on the first line of input. It stands for the number of expressions to follow. Each expression consists of a single line containing only lowercase letters, operators (+, -, *, /) and parentheses (( and )). The letters are variables that can have any value, operators and parentheses have their usual meaning. Multiplication and division have higher priority then subtraction and addition. All operations with the same priority are computed from left to right (operators are left-associative). There are no spaces inside the expressions. No input line contains more than 250 characters.
Output
 
Print a single line for every expression. The line must contain the same expression with unneeded parentheses removed. You must remove as many parentheses as possible without changing the semantics of the expression. The semantics of the expression is considered the same if and only if any of the following conditions hold: 
 
The ordering of operations remains the same. That means "(a+b)+c" is the same as "a+b+c", and "a+(b/c)" is the same as "a+b/c". 
The order of some operations is swapped but the result remains unchanged with respect to the addition and multiplication associativity. That means "a+(b+c)" and "(a+b)+c" are the same. We can also combine addition with subtraction and multiplication with division, if the subtraction or division is the second operation. For example, "a+(b-c)" is the same as "a+b-c". 
 
You cannot use any other laws, namely you cannot swap left and right operands and you cannot replace "a-(b-c)" with "a-b+c". 
 
Sample Input
 
8
(a+(b*c))
((a+b)*c)
(a*(b*c))
(a*(b/c)*d)
((a/(b/c))/d)
((x))
(a+b)-(c-d)-(e/f)
(a+b)+(c-d)-(e+f)
Sample Output
 
a+b*c
(a+b)*c
a*b*c
a*b/c*d
a/(b/c)/d
x
a+b-(c-d)-e/f

a+b+c-d-(e+f)


解法:

//本题是对实际过程的模拟。实质就是一个搜索加上分类讨论。先讨论搜索,因为要去掉括号,从最外面去括号考虑的情况太复杂了,所以就从能找到的第一个最里面的括号开始去,去到最外面一层,然后重复这个过程,和深度优先搜索有点类似。具体过程看两个DD之间标出的段落,这就是全部的搜索过程了。然后是分类讨论,这里分类的情况很多,影响一对括号能不能去掉主要受三个因素的影响,括号前面的以一个符号('+','-','*','/','('和左括号是第一个符号),右括号后面的第一个符号('+','-','*','/',')'和右括号是最后一个符号),还有左括号和右括号包围起来的式子的情况。最简单的情况是JJ包围起来的情况,因为和左右括号中间式子的情况没有关系,可以单独列出来。然后就比较麻烦了。要讨论左右括号中间式子的情况(见函数int GetOpeCond(string::iterator,string::iterator)),然后把得到的情况和第一、第二种情况结合,才能最终的到这一对括号能不能去掉。

//本题用C++语言做的原因,因为C++提供了对string删除某个字符的功能,用在这里可以减少代码的数量,用C中的char数组写太麻烦了。

#include<iostream>
#include<fstream>
#include<string>
#include<iterator>
#include<cstdlib>
using namespace std;

ifstream fin("C:\\data39.in");

string str;
int N;

//对左右括号包围起来的式子的讨论,在要讨论的式子中,(A*B+C-D/E)看成一个变量,因为要讨论的式子中的括号在前面已经证明不能去掉了,括号中间的标点符号的情况对最终结果没有影响,PP中的代码对这种情况作了处理
int GetOpeCond(string::iterator beg,string::iterator end)
{
	int opCnt=0;//影响最终结果的标点符号的数量opCnt=0时,说明这个式子的格式为(A);
	int OpeCond=2;//OpenCond为0时,式中有‘+’或‘-’,为1时,式中除了有‘*’,还有‘/’,为2时,只有‘*’;
	for(string::iterator iter=beg;iter!=end;++iter)
	{
		if(*iter=='+'||*iter=='-')
		{
			++opCnt;
			OpeCond=0;
		}
		else if(*iter=='/')
		{
			++opCnt;
			if(OpeCond==2)
				OpeCond=1;
		}
		else if(*iter=='*')
			++opCnt;
		//PP
		else if(*iter=='(')
		{
			int cnt=0;
			while(iter!=end)
			{
				if(*iter=='(')
					++cnt;
				if(*iter==')')
					if(--cnt==0)
						break;
				++iter;
			}
		}
		//PP
	}
	if(!opCnt)
		return -1;
	else{
		return OpeCond;
	}
}

void search()
{
	string::iterator left=str.begin();
	string::iterator right=str.begin();
	while(right!=str.end())
	{
		//DD
		while(*right!=')')
		{
			if(*right=='(')
				left=right;
			++right;
		}
		//DD
		//JJ
		if((left==str.begin()||*(left-1)=='+'||*(left-1)=='(')&&(right+1==str.end()||*(right+1)=='+'||*(right+1)=='-'||*(right+1)==')'))
		{
			str.erase(left);
			--right;
			str.erase(right);
		}
		//JJ
		else
		{
			int sign=GetOpeCond(left+1,right);
			if(sign==-1)
			{
				str.erase(left);
				--right;
				str.erase(right);
    			}
			else if((left==str.begin()||*(left-1)=='-')&&sign!=0)
			{
				str.erase(left);
				--right;
				str.erase(right);
			}
			else if(left==str.begin())
			{
				str.erase(left);
				--right;
				str.erase(right);
			}
			else if((*(left-1)=='*'||*(left-1)=='(')&&(sign==2||sign==1))
			{
				str.erase(left);
				--right;
				str.erase(right);
			}
			else
			{
				--left;
				++right;
			}
		}
		int cnt=0;
		//D
		while(left!=str.begin())
		{
			if(*left==')')
				++cnt;
			if(*left=='(')
			{
				if(cnt--==0)
					break;
			}
			--left;
		}
		//D
	}
}

int main()
{
    fin>>N;
    int i=0;
    while(i<N)
    {
    ++i;
	fin>>str;
	search();
	cout<<str<<endl;
    }
	system("pause");
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值