题解 P2229 【[HNOI2002]沙漠寻宝】

· · 题解

写在前面

实际上已近写过一篇这个题的题解了,这次只是稍作修改,压缩了以前又臭又长的代码,顺便再说明一下解题思路。

遇到的问题

一看这个题就知道是模拟,但是怎么模拟呢?

首先,读入与存储问题,如何准确的读入以及如何将输入的代码存起来。

其次,也是最难的,模拟程序运行,其中最关键的就是如何模拟循环的运行。

再者,计算器的问题,赋值语句与循环次数的计算。

解决方案

1.读入与存储,开一个二维的char数组(string也行,个人喜好),使用scanf("%s",s)读入,遇到空格跳过。

2.运行过程,其他语句不多说,就讲讲最关键的循环语句吧,看到有很多大佬都是用栈来模拟,个人不太习惯用栈模拟,于是用了类似于递归的方法,一层层进入,再退出。

3.有关计算器,由于题中给出了语句的执行次数的总和小于2000000次,那么计算器完全可以使用递归代替栈来写,并且完全不用担心会超时。

最后附上AC代码,代码中有解释

#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <cmath>
#include <algorithm>
#define MAXN 1001
using namespace std;

//函数总览,后面有解释
void read();
void work();
void find();
void write(char x[]);
int check(char x[]);
void run(char x[]);
void pre(char x[],int l,int r);
int calc(char x[],int l,int r);
void run_loo(char x[]);
int run_fu(char x[],int in,int enk);

char str[MAXN][MAXN],s[MAXN];
int tot=0,h=1,f[MAXN],ff[MAXN],sh[30];
const int sta=1,en=2,loo=3,con=4,wri=5,bre=6,fu=7;

//读入,处理掉空格
void read(){
    while((scanf("%s",s))!=EOF){
        if(s[0]!=' '){
            strcpy(str[++tot],s);
        }
    }
}

//输出
void run_wri(char x[]){
    ++h;
    printf("%d\n",run_fu(str[h],0,strlen(str[h])-1));
}

//预处理,找到循环的开始与结束
void find(){
    int v[MAXN],v1=0;
    for(int i=2;i<tot;i++){
        if(check(str[i])==loo){
            v1++;
            v[v1]=i;
        }else if(check(str[i])==en){
            f[v[v1]]=i;
            v1--;
        }
    }
}

//循环语句的递归实现
void run_loo(char x[]){
    ++h;
    int t=run_fu(str[h],0,strlen(str[h])-1),tmp=h-1;
    for(int i=1;i<=t;i++){
        ++h;
        while(check(str[h])!=en){
            if(check(str[h])==loo){
                run_loo(x);
            }else if(check(str[h])==con){
                break;
            }else if(check(str[h])==bre){
                h=f[tmp];
                return;
            }
            run(str[h]);
            ++h;
        }
        h=tmp+1;
    }
    h=f[tmp];
}

//每次使用计算器之前的预处理,为了处理表达式中有括号匹配的情况
void pre(char x[],int l,int r){
    int v[MAXN],tot=0;
    for(int i=l;i<=r;++i){
        if(x[i]=='('){
            v[++tot]=i;
        }else if(x[i]==')'){
            ff[v[tot]]=i;
            --tot;
        }
    }
}

//递归实现简单计算器
int calc(char x[],int l,int r){
    if(l==r&&x[l]>='a'&&x[l]<='z') return sh[x[l]-'a'];
    if(x[l]=='('&&x[r]==')'&&ff[l]==r){
        return calc(x,l+1,r-1);
    }
    int jia=0,cheng=0,isjia=0,ischeng=0,fa=0,isfa=0;
    for(int i=l;i<=r;++i){
        if(x[i]=='+') jia=i,isjia=1;
        else if(x[i]=='*') cheng=i,ischeng=1;
        else if(x[i]=='/') cheng=i,ischeng=0;
        else if(x[i]=='-') jia=i,isjia=0;
        else if(x[i]=='^') isfa=1,fa=i;
        else if(x[i]=='(') i=ff[i]-1;
    }
    if(jia!=0){
        if(isjia==1) return (calc(x,l,jia-1)+calc(x,jia+1,r));
        else return (calc(x,l,jia-1)-calc(x,jia+1,r));
    }else if(cheng!=0){
        if(ischeng==1) return (calc(x,l,cheng-1)*calc(x,cheng+1,r));
        else return (calc(x,l,cheng-1)/calc(x,cheng+1,r));
    }else if(isfa!=0){
        return (int)pow(calc(x,l,fa-1)*1.0,calc(x,fa+1,r)*1.0);
    }else if(jia==0&&cheng==0&&isfa==0){
        int tmp=0;
        for(int i=l;i<=r;++i){
            tmp=(tmp*10+(x[i]-'0'));
        }
        return tmp;
    }
}

//赋值语句的运行,调用calc()函数计算
int run_fu(char x[],int in,int enk){
    memset(ff,0,sizeof(ff));
    pre(x,in,enk);
    int res=calc(x,in,enk);
    return res;
}

//判断是哪一种语句
int check(char x[]){
    if(x[1]=='='){
        return fu;
    }else if(x[0]=='s'){
        return sta;
    }else if(x[0]=='e'&&x[1]=='n'){
        return en;
    }else if(x[0]=='l'&&x[1]=='o'){
        return loo;
    }else if(x[0]=='c'&&x[1]=='o'){
        return con;
    }else if(x[0]=='w'&&x[1]=='r'){
        return wri;
    }else if(x[0]=='b'&&x[1]=='r'){
        return bre;
    }else{
        return -1;
    }
}

//运行每一句语句
void run(char x[]){
    int k=check(x);
    switch(k){
        case 3:run_loo(x); break;
        case 5:run_wri(x); break;
        case 7:sh[x[0]-'a']=run_fu(x,2,strlen(x)-1); break;
        default:break;
    }
}

//循环每一句语句
void work(){
    while(h<=tot){
        run(str[h]);
        ++h;
    }
}

int main(){ 
    read();
    find();
    work();
    return 0;
}

有问题可在评论区留言哟。(●'◡'●)。~~~