cqbzoj 1158 剔除多余括号

问题 H(1158): 剔除多余括号

时间限制: 1 Sec   内存限制: 64 MB

题目描述

输入一个含有括号的四则运算表达式,要求去掉可能含有的多余的括号,结果要保持原表达式中变量和运算符的相对位置不变,且与原表达式等价 , 不要求化简。另外不考虑 '+' '-' 用作正负号的情况,即输入表达式不会出现 (+a) (-a) 的情形。

输入

第1行:一个字符串表示要整理的表达式

输出

第1行:整理后的结果

样例输入

((a+b)*f)-(i/j)

样例输出

(a+b)*f-i/j


要求处理输入字符串,首先,对于任意的表达式,我们都可以找的一个最后运算的运算符op,op左、右侧的表达式必定可以分别处理,于是我们采用二分的方法。

先把要处理的表达式左右括号全部删掉,再通过括号内与括号外的运算优先级判断该括号是否必须存在,如果必须,就还原括号。


至于如何判断运算优先级,就要看最后运算的运算符op,即断点的优先级。

设左区间的断点为op1,右区间的断点为op2,当前区间为op

则(A op1 B)op (C op2 D)中

if(优先级(op1)< 优先级(op))

还原左区间括号;

if(优先级(op)> 优先级(op2))

还原右区间括号;

if(op为 ' - ' 或 ' / ')特别处理;

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;

#define MAXN 100000
#define MAXM
#define INF 0x3f3f3f3f
#define LL long long

char A[MAXN+10];

int find_another(int x)//查询前括号
{
	int cnt=0;
	for(int i=x;;--i)
	{
		if(A[i]==')')
			++cnt;
		else if(A[i]=='(')
			--cnt;
		if(!cnt)return i;
	}
}

int find_breakpoint(int l,int r)//查询当前区间断点
{
	int pos=0;
	for(int i=r;i>=l;--i)
	{
		if(A[i]==')')//跳过高优先级区间
			i=find_another(i);
		else if((A[i]=='*'||A[i]=='/')&&!pos)//次一级断点
			pos=i;
		else if(A[i]=='+'||A[i]=='-')//运算级最低,必为断点
			return i;
	}
	
	return pos;
}

void dfs(int l,int r,char &op)//二分处理字符串
{
	while(A[r]==')'&&find_another(r)==l)//删除当前区间两端括号
	{
		A[l]=A[r]=0;
		++l,--r;
	}
	
	if(l>=r)
	{
		op=0;
		return;
	}
	
	int pos=find_breakpoint(l,r);
	char op1,op2;
	dfs(l,pos-1,op1);
	dfs(pos+1,r,op2);
	
	op=A[pos];
	if((op1=='-'||op1=='+')&&(op=='*'||op=='/'))
		A[l]='(',A[pos-1]=')';
	if((op=='/'&&op2)||((op=='-'||op=='*')&&(op2=='+'||op2=='-')))
		A[pos+1]='(',A[r]=')';
}

int main()
{
	gets(A+1);
	int len=strlen(A+1);
	
	char op;
	dfs(1,len,op);
	
	for(int i=1;i<=len;++i)
		if(A[i])printf("%c",A[i]);
	puts("");
}

  • 6
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值