bzoj1561: [JSOI2009]去括号

本文介绍了如何解决bzoj1561题目,即JSOI2009年的去括号问题。通过使用栈处理括号配对,并计算每个运算符的优先级,来确定哪些括号可以被去除。详细步骤包括初始化优先级变量,根据括号类型调整优先级,处理特殊情况如双括号,并采用深度优先搜索(DFS)进行操作。在DFS过程中,比较括号内运算符优先级,判断能否去除括号并相应改变符号。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

传送门
好的乱搞题一道。
先用栈处理出每个左或右括号对应的另一个右或左括号的下标。
然后求每个运算符的优先级。
具体是这样的:
(1)定义一个临时变量j,表示当前位置的优先级,然后遍历表达式,初始j为1。
(2)进入一个括号j加2。(即遇到左括号)
(3)+和-的优先级直接赋j。
(4)*和/的优先级赋j+1。
(5)退出一个括号j减2。(即遇到右括号)
当然我们要特判掉((sth))的情况,只要加2就ok辣。
预处理所有的优先级之后,就可以去括号了。
从1开始dfs。(当然为了方便处理,我们在原串两边加上一对括号。1号位置是那个左括号。)
每次dfs,先遍历串,处理之后的括号,保证正确性,同时还可以得到右括号的位置。
然后获取这两个括号左右位置的运算符的优先级,取最大的。
看括号内部是否有+或-号,这个不是直接看字符串,而是用优先级的大小关系判断。
如果有,那么不能去掉当前括号,返回。
如果没有,那么可以去掉,然后变号。
变号时,如果前面是减号,那么+变-,-变+。
如果前面是除号,那么变/,/变
码量略大。

#include<cmath>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define N 305
using namespace std;
int n,a[N],le[N],ri[N],sta[N],top,T;
char s[N];
int dfs(int l){
    int r;
    for (r=l+1;s[r]!=')';r++)
        if (s[r]=='(') r=dfs(r);
    int k=max(a[l-1],a[r+1]),pos;
    for (pos=l+1;pos<r;pos++)
        if (a[pos]==k+1) break;
    if (pos<r) return r;
    s[l]=s[r]='$';
    int cnt=0;
    if (s[l-1]=='-')
        for (int i=l+1;i<r;i++){
            if (s[i]=='(') cnt++;
            else if (s[i]==')') cnt--;
            if (!cnt)
                if (s[i]=='-') s[i]='+';
                else if (s[i]=='+') s[i]='-';
        }
    if (s[l-1]=='/')
        for (int i=l+1;i<r;i++){
            if (s[i]=='(') cnt++;
            else if (s[i]==')') cnt--;
            if (!cnt)
                if (s[i]=='*') s[i]='/';
                else if (s[i]=='/') s[i]='*';
        }
    return r;
}
void solve(){
    memset(a,0,sizeof(a));
    scanf("%s",s+2); n=strlen(s+2);
    s[1]='('; s[n+2]=')';
    top=0;
    for (int i=1;i<=n;i++)
        if (s[i]=='(') sta[++top]=i;
        else if (s[i]==')'){
            ri[sta[top]]=i;
            le[i]=sta[top];
            top--;
        }
    a[0]=a[n+1]=1;
    for (int i=1,j=1;i<=n;i++)
        if (s[i]=='('&&(s[i-1]!='('||s[ri[i]+1]!=')')) j+=2;
        else if (s[i]==')'&&(s[i+1]!=')'||s[le[i]-1]!='(')) j-=2;
        else if (s[i]=='+'||s[i]=='-') a[i]=j;
        else if (s[i]=='*'||s[i]=='/') a[i]=j+1;
    dfs(1);
    for (int i=2;i<=n+1;i++)
        if (s[i]!='$') putchar(s[i]);
    puts("");
}
int main(){
    scanf("%d",&T);
    while (T--) solve();                    
}
说明 很久就想编一个这样的计算器,只可惜一直没什么思路,最近突然灵感来了,所以就写下 这个程序。现在还在测试阶段,所以功能不是很完善。 程序功能:基本的表达式运算,可以自定义函数跟常量,分别保存在 “常数.txt” 和 “函数.txt”,方便自己添加。双击相应的函数名或常数名就可以将函数或常量添加到表达式中。 计算过程只能当表达式只有一行时有效。 实例1:计算sqr(19+tan(98)*tan(91)-sin(122)*(5*5-(19-11)))/2 计算过程sqr(19+tan(98)*tan(91)-sin(122)*(5*5-(19-11)))/2 =sqr(19+-7.11536972238419*tan(91)-sin(122)*(5*5-(19-11)))/2 =sqr(19+-7.11536972238419*-57.2899616307588-sin(122)*(5*5-(19-11)))/2 =sqr(19+-7.11536972238419*-57.2899616307588-.848048096156426*(5*5-(19-11)))/2 =sqr(19+-7.11536972238419*-57.2899616307588-.848048096156426*(5*5-8))/2 =sqr(19+-7.11536972238419*-57.2899616307588-.848048096156426*17)/2 =20.3032618253667/2 =10.1516309126834 实例2:计算 a=34 b=55 c=a+1 圆的面积(c) a*b c=a+b 圆的面积(c) 以下是计算结果: 圆的面积(c)=3848.4510006475 a*b=1870 圆的面积(c)=24884.5554090847 内置函数: !(x) - x 的阶乘 lg(x),log(x) 以10为底的对数 ln(x) 以 e为底x的对数 pow(x,y) x的y方次幂 prime(x) 判定x是否是素数,如果是直接将s2返回,否则将其各因子用连乘返回 sqr(x),sqrt(x) - x 的二次方根 arcsin(x) - x 的反正弦 arccos(x) - x 的反余弦 arcsec(x) - x 的反正割 arccsc(x) - x 的反余割 atn(x),arctg(x) - x 的反正切 arcctg(x) - x 的反余切 sin(x) - x 的正弦 cos(x) - x 的余弦 sec(x) - x 的正割 csc(x) - x 的余割 tg(x),tan(x) - x 的正切 ctg(x) - x 的余切 harcsin(x) - x 的反双曲正弦 harccos(x) - x 的反双曲余弦 harcsec(x) - x 的反双曲正割 harccsc(x) - x 的反双曲余割 harctg(x),harctan(x) - x 的反双曲正切 harcctg(x) - x 的反双曲余切 hsin(x) - x 的双曲正弦 hcos(x) - x 的双曲余弦 hsec(x) - x 的双曲正割 hcsc(x) - x 的双曲余割 htg(x),htan(x) - x 的双曲正切 hctg(x) - x 的双曲余切 有什么意见或建议可以跟我联系Email: ldm.menglv@gmail.com
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值