题解 P2027 【bf】
Sweetlemon
2017-02-03 10:51:56
这题是编写BrainF**k的解释器,我的程序把这个过程分为三部分:读入代码和输入缓冲——预处理代码(主要是循环)——逐字符解释(执行)代码。
读入没什么可说的,但是要注意忽略"$"前/后的空格。
预处理主要是为了提高执行效率,方便循环的快速跳转。我的上一次提交就是没有用预处理,结果TLE了。因此,避免重复工作是很必要的。
有了预处理的基础,逐字符解释代码也就不难了。只要根据题目的资料(当然,也可以结合Wikipedia上的说明,下面我会发一个Wiki的截图,方便无法访问Wiki的朋友们),写出适当的代码,就好了。
下面发送一下Wiki对BrainF**k的解释(为了避免洛谷的水印影响阅读,稍微调整了版式):
![](https://cdn.luogu.com.cn/upload/pic/4178.png)
最后是AC(6ms,8515kb)的代码:
```cpp
#include <stdio.h>
#include <string.h>
int main(void){
char codes[30001];//代码
char inputs[30001];//输入缓冲区
signed char data[30000]={0};//程序数据,需要初始化为零
int down[30001],up[30001],tstack[15000];//down为左中括号到右中括号的索引,up为右中括号到左中括号的索引,tstack为预处理时的括号栈
char t;//读取时用
signed char * pdata;//数据指针
int i=0,j=0,k=0,ncodes,ninputs; //i记录codes的索引,j记录inputs的索引,k记录tstack的索引
while ((t=getchar())!='$')
if (strchr("><.,+-[]",t)) //只记录代码的字符
codes[i++]=t;
ncodes=i; //为代码的总字符数
codes[ncodes]='\0';
getchar();//跳过'$'后的空格
while ((t=getchar())!='$')
inputs[j++]=t;
ninputs=j-1;//为输入的总字符数
inputs[ninputs]='\0';
//读入完成,开始预处理
for (i=0;i<ncodes;i++){
switch (codes[i]){
case '[':
tstack[k++]=i;//入栈
break;
case ']':
down[tstack[--k]]=i;//出栈、记录
up[i]=tstack[k];
break;
}
}
//预处理完成,开始解释
i=0,j=0,pdata=data; //索引、数据指针归零
while (i<ncodes){//遍历代码
switch (codes[i]){
case '<':
pdata--;
break;
case '>':
pdata++;
break;
case '.':
putchar(*pdata);
break;
case ',':
if (j<ninputs)
*pdata=inputs[j++];
else
*pdata=-1;//此时已读完输入缓冲,置为-1
break;
case '+':
(*pdata)++;
break;
case '-':
(*pdata)--;
break;
case '[':
if (!(*pdata))//如果不执行循环,直接跳到对应]处
i=down[i];
break;
case ']':
if (*pdata){//如果继续执行循环,跳到[处
i=up[i];
}
break;
}
i++;//执行下一行代码
}
return 0;
}
```