信息学奥赛一本通(C++版) 第三部分 数据结构 第一章 栈

 信息学奥赛一本通(C++版) 第三部分 数据结构 第一章 栈

http://ybt.ssoier.cn:8088/

//1331 【例1-2】后缀表达式的值
//该题 一本通 的在线测评,一提交就说超时,同样的题目 在洛谷
//https://www.luogu.org/problem/show?pid=1449 同样的代码,一提交就AC
//P1449 后缀表达式
//以下代码为 洛谷AC 代码,却在 一本通 超时代码
//2017-10-26 21:30
//将读取代码修改,不再超时,却报答案错误,看来有必要翻翻原书了。
//下述代码,在洛谷再次通过
//输入:
//16 9 4 3 +*-@

//输出:
//-47
 
//1331 【例1-2】后缀表达式的值
//该题搁置很久,《信息学奥赛一本通(C++版)》题解已不适合该题了,翻看该题
//发现:添加了提示“提示:输入字符串长度小于250,参与运算的整数及结果之绝对值均在264范围内,如有除法保证能整除。”
//将int改成long long 提交,AC 2017-12-25  
#include <stdio.h>
#include <string.h>
char a[10000];
long long stack[1000],top=-1;//此处写成 int stack[1000],top=-1;
int main(){
    long long k=0,i,len,b,tag,d,e,f;//此处写成 int k,i,len,b,tag,d,e,f;
    char c;
    gets(a);
    len=strlen(a);
    i=0;
    while(i<len){
        b=0,tag=0;
        while(i<len&&'0'<=a[i]&&a[i]<='9')b*=10,b+=a[i]-'0',i++,tag=1;
        if(tag)top++,stack[top]=b;
        else if(a[i]=='+'||a[i]=='-'||a[i]=='*'||a[i]=='/'){
            d=stack[top],top--;
            e=stack[top],top--;
            switch(a[i]){
                case '+':
                    f=e+d;
                    break;
                case '-':
                    f=e-d;
                    break;
                case '*':
                    f=e*d;
                    break;
                case '/':
                    f=e/d;
                    break;
            }
            top++;
            stack[top]=f;
            i++;
        }else
            i++;
    }     
    printf("%lld",stack[top]);
    return 0;
}




//1331 【例1-2】后缀表达式的值
//该题 一本通 的在线测评,一提交就说超时,同样的题目 在洛谷
//https://www.luogu.org/problem/show?pid=1449 同样的代码,一提交就AC
//P1449 后缀表达式
//以下代码为 洛谷AC 代码,却在 一本通 超时代码
//2017-10-26 21:30
#include <stdio.h>
#include <string.h>
char a[10000];
int stack[1000],top=-1;
int main(){
    int k=0,i,len,b,tag,d,e,f;//此处写成 int k,i,len,b,tag,d,e,f;
    char c;
    while((c=getchar())!='@')
        a[k++]=c;
    a[k]='\0';
    len=strlen(a);
    i=0;
    while(i<len){
        b=0,tag=0;
        while(i<len&&'0'<=a[i]&&a[i]<='9')b*=10,b+=a[i]-'0',i++,tag=1;
        if(tag)top++,stack[top]=b;
        else if(a[i]=='+'||a[i]=='-'||a[i]=='*'||a[i]=='/'){
            d=stack[top],top--;
            e=stack[top],top--;
            switch(a[i]){
                case '+':
                    f=e+d;
                    break;
                case '-':
                    f=e-d;
                    break;
                case '*':
                    f=e*d;
                    break;
                case '/':
                    f=e/d;
                    break;
            }
            top++;
            stack[top]=f;
            i++;
        }else
            i++;
    }     
    printf("%d",stack[top]);
    return 0;
}

//1353 表达式括号匹配(stack)
#include <stdio.h>
#include <string.h>
int stack[1000],top=-1;
char a[10000];
int main(){
    int i,len;
    scanf("%s",a);
    len=strlen(a);
    for(i=0;i<len;i++)
        if(a[i]=='(')top++,stack[top]=1;//( 1
        else if(a[i]==')'){
            if(top>=0)top--;
            else top++,stack[top]=2;//) 2
        }
    if(top==-1)printf("YES");
    else printf("NO");
    return 0;
}

//1354 括弧匹配检验
//该题说明如下:
//题目中的字符串根本不能用,夹杂着中文的括号,英文的空格
//要进行测试,读者只能自行输入英文的符号2017-10-26 22:27
#include <stdio.h>
#include <string.h>
char a[1000];
int stack[1000],top=-1;//(1 )2 [3 ]4
int main(){
    int i,len;
    scanf("%s",a);
    len=strlen(a);
    for(i=0;i<len;i++)
        if(a[i]=='(')top++,stack[top]=1;
        else if(a[i]==')'){
            if(top==-1)top++,stack[top]=2;
            else if(stack[top]==1)top--;
            else top++,stack[top]=2;
        }else if(a[i]=='[')top++,stack[top]=3;
        else if(a[i]==']'){
            if(top==-1)top++,stack[top]=4;
            else if(stack[top]==3)top--;
            else top++,stack[top]=4;
        }
    if(top==-1)printf("OK");
    else printf("Wrong");
    return 0;
}

//1355 字符串匹配问题(strs)
//一月前编写此题,一个多小时,提交,未果,搁置
//http://blog.csdn.net/ametake/article/details/43987407此文写得不错,吸引本人原因,代码写得够短
//第一步,将字符映射成数字,处理起来方便
//样例通过,提交,测试点2,3,5答案错误
//反复阅读代码,觉得所有情况都考虑周全,很需要上述三个测试点数据,无奈,在http://codevs.cn/problem/3543/提交研究
//在上述网站找到一组测试数据:
//输入:
//6
//{}{}<><>()()[][]
//{{}}{{}}<<>><<>>(())(())[{}][[]]
//{{}}{{}}<<>><<>>(())(())[[]][[]]
//{<>}{[]}<<<>><<>>>((<>))(())[[(<>)]][[]]
//><}{{[]}<<<>><<>>>((<>))(())[[(<>)]][[]]
//([])
//输出:
//YES
//NO
//YES
//YES
//NO
//NO
//对照上述例子,发现,top未在每次读取新字符串时,初始化为0,难怪这个错误怎么找都找不到,原来是初始化的问题。
//codevs里提交AC,ybt里提交AC,2017-12-9 12:33
#include <stdio.h>
#include <string.h>
char a[]={'{','[','(','<','}',']',')','>'},s[300];//{0 }4 [1 ]5 (2 )6 <3 >7
int b[300],stack[300],top;//b[i]与s[i]一一映射
int main(){
    int t,len,i,j,k,flag;//flag合法,非法标记
    scanf("%d",&t);
    while(t--){
        flag=1,top=0;//漏了top=0这句,查了好久
        scanf("%s",s);//此处写成 scanf("%d",s); 尽出昏招
        len=strlen(s);
        for(i=0;i<len;i++)//建立字符与数字的一一映射关系
            for(j=0;j<8;j++)
                if(s[i]==a[j]){
                    b[i]=j;
                    break;
                }
        i=0;
        while(i<len){//是否匹配处理
            //printf("b[%d]=%d\n",i,b[i]);
            if(b[i]<=3)//b[i]元素想要入栈
                if(top==0||b[i]>=stack[top]){//b[i]元素可以入栈,top==0栈为空,或栈内符号满足嵌套关系
                    top++,stack[top]=b[i];
                }else{//b[i]元素无法入栈,该组数据非法,结束该组数据处理
                    flag=0;
                    break;
                }
            else if(b[i]>=4){//b[i]元素希望与栈内元素配对
                if(top>0&&stack[top]+4==b[i]){//首先栈内要有元素,同时判断是否配对
                    top--;
                }else{//无法配对,结束 该组数据处理
                    flag=0;
                    break;
                }
            }
            i++;
        }
        if(top)printf("NO\n");//栈内有元素,匹配不成功
        else if(flag==1)printf("YES\n");//栈内无元素,匹配成功
        else printf("NO\n");//栈内无元素,匹配不成功
    }
    return 0;
}
//1356 计算(calc)
//http://www.oier.cc/ssoj2461%e8%ae%a1%e7%ae%97/研究此文代码,思路摘抄如下:
//一个数据栈,一个运算符栈,遇到数据,数据进数据栈,遇到运算符,运算符进运算符栈。
//最后计算的时候,从栈顶开始计算:取出一个运算符和两个数据,把计算结果压回数据栈,
//直到运算符栈为空,数据栈的那个数据即是答案。
//按照上述方法,则靠近栈顶的运算符优先级高,靠近栈底的运算符优先级低。
//如果在进栈过程中,出现栈顶的优先级比前一个运算符优先级低(不高于),怎么办?
//那肯定是先计算前面的运算符。因此,在运算符压栈过程中,读入后一个数据前(43行代码),
//如果前面有应该先算的运算符(优先级高或者同级),则先算前面的。
//最后一个问题,就是括号问题了。左括号是在获取数据时遇到的,这是先把括号当运算符压栈,
//i+1略过这个左括号后再继续获取数据。当遇到右括号时,运算符栈中,前一个左括号后面的运算符都要先算,
//则一直算到左括号(39行代码)。在判断优先级时,括号优先级很高,但左括号不能运算,故遇到括号不算,
//至少在遇到右括号时一直退栈。
//抄写此代码,提交AC。
//经测试,http://ybt.ssoier.cn:8088 该题后台测试数据有误,基本可以确定后台测试数据是根据 系统自带的 pow函数算出,请注意pow函数 返回值时double,转成整数,存在误差
//采用自编的my_pow函数 ,测试点2-4 答案错误,基本确认,这三个测试点的输出数据是错误的
//提供一组测试样例
//输入:
//(1-2+3-4+5-6+7-8+9-10+(10^2*2+2)/2-1)^3
//输出:
//857375
//采用 系统自带 pow 针对上述样例 算出过程如下:
//a[n-1]=10 a[n]=2
//a[n-1]=99
//a[n-1]=94 a[n]=3
//a[n-1]=830584
//830584
//故 经验证 测试点2-4 的输出数据 有误。2018-1-5
//编写下来的感觉是,对i的处理还需改进,什么时候i++,什么时候还是用i,很依赖编程者的思维
//样例通过,提交AC 2018-1-5 21:39
#include <stdio.h>
#include <math.h>
int a[2000],n=0,i=0,m=0;//数据栈 n标记数据栈中位置 i标记字符串位置 m标记运算符栈中位置 请注意i=0
char s[2000],b[2000],c[300];//s字符串,b运算符栈 ,运算符优先级设置
void compute(){
    switch(b[m-1]){//自左往右计算
        case '+':a[n-1]+=a[n];break;
        case '-':a[n-1]-=a[n];break;
        case '*':a[n-1]*=a[n];break;
        case '/':a[n-1]/=a[n];break;
        case '^':a[n-1]=pow(a[n-1],a[n]);break;//此处不用系统自带的pow无法通过所有测试点
    }
    b[m-1]=b[m],m--,n--;//出栈,运算符栈,数据栈
}
int can(){
    if(c[b[m-1]]==4||c[b[m]]==4)return 0;//判断是否有'(' 左括号
    if(c[b[m-1]]>=c[b[m]])return 1;//此处写成if(c[b[m-1]]>c[b[m]])return 1;//左边运算符优先级高于右边运算符,可以计算
    return 0;//其它情况都是 无法计算
}
int getint(){//获得整数
    int ans=0;
    if(s[i+1]=='('){//遇到'('的处理
        b[++m]=s[++i];//将'('存入 运算符栈
        return getint();//递归调用
    }
    while('0'<=s[++i]&&s[i]<='9')ans=ans*10+s[i]-'0';//注意此处技巧s[++i]//脱出循环时i已经指向非整数位置
    return ans;
}
int main(){
    c['+']=c['-']=1,c['*']=c['/']=2,c['^']=3,c['(']=c[')']=4;//设置运算符优先级
    scanf("%s",s+1);//存储字符串,从 s[1]开始
    a[++n]=getint();
    while(s[i]=='+'||s[i]=='-'||s[i]=='*'||s[i]=='/'||s[i]=='^'||s[i]==')'){//此句写得很妙,无需判断字符串长度了//右括号
        b[++m]=s[i];
        if(s[i]==')'){//右括号要单独处理
            while(b[m-1]!='(')compute();
            m-=2,i++;//i++目的,读取')',若是其他运算符,在getint()函数里,会运算下一个i值,即i+1//此句写成m-=2;//弹出左右括号
            continue;
        }
        while(m>1&&can())compute();
        a[++n]=getint();//此处写到大的while循环之外
    }
    m++;//必须空算一次
    while(m>1)compute();
    printf("%d",a[1]);
    return 0;
}


//1357 车厢调度(train)
//https://www.cnblogs.com/zxqxwnngztxx/p/6679727.html代码写得精炼
//该题思维量比较大,2017-12-11 AC
#include <stdio.h>
int a[1010],b[1010],top=0;
int main(){
    int n,i,cur;
    scanf("%d",&n);
    for(i=1;i<=n;i++)scanf("%d",&a[i]);//a[i]为到达B站的车厢
    b[0]=0;
    for(i=1,cur=1;i<=n;i++){//模拟进栈,到达A站,出栈,到达B站,模拟
        while(b[top]<a[i])top++,b[top]=cur,cur++;//比a[i]小的车厢都要在栈中 cur为需要进栈的车厢,这个要求技巧比较高
        if(b[top]==a[i])top--;//将a[i]弹出栈
        else{
            printf("NO");
            return 0;
        }
    }
    printf("YES");
    return 0;
}


猜你喜欢

转载自blog.csdn.net/mrcrack/article/details/78358956
今日推荐