题目较复杂。模拟+字符串处理
大致题意为:给定一个特定程序,有如下语句组成:
1)BEGIN表示开始
3)OP interger(非负)表示操作interger次
4)LOOP n 或者是 LOOP interger(非负),表示循环n次或者interger次
5)END与LOOP和BEGIN对应分别表示循环的结束和程序的结束(类似于伪代码)
其它为空格或换行,空格或换行可以出现在任何位置,除了上述关键字和interger整数。
由题意可知:LOOP必须与END匹配,且LOOP必须在与之匹配的END之前。OP操作可以出现在BEGIN和END之间的任意位置。
分析如下:由于LOOP与最近的END匹配,而OP操作的次数是最内层循环到最外层循环次数的乘积,且BEGIN必为程序第一句,END必为程序最后一句,例如:
BEGIN
LOOP n
OP 3
LOOP 3
OP 4
END
END
END
可知OP3操作n*3次,而OP4操作n*3*4次,我们可以利用类似堆栈的结构存储各循环层次,这样在输入的同时就可以判断OP操作的镶嵌循环层次,以及每层次上的循环个数,然后计算该操作的总共的循环次数,累加到结果中即可。
这里用数组存储结果,n幂数字0——10分别初始化为0,然后在输入的同时按照上述的方法计算每个OP的循环次数,累计到相应的幂次项即可。
这里再说明一下如何动态的更新层次:每遇到LOOP就进数组(下标增大),若在与该LOOP对应的END前OP操作,则OP操作的循环镶嵌层次即为目前的最大层次,计算完循环次数后,若遇到END,则小标减一,表示循环镶嵌层次减少一个层次;若遇到LOOP则要进数组,循环镶嵌层次增加一个层次,这就是动态维护当前OP所在位置循环镶嵌层次的过程(与普通的for循环是一样的道理)。
另外就是要注意:
1)处理字符输入时,空格和行换是不同的字符,但均当作无效符号处理
2)处理OP 0操作的方法,由于OP 0表示操作次数为0次,故可以省略该操作,因为题目要求的是有效操作次数,即使循环层次再深,若为0则有效操作也为0次(很容易理解)
3)处理LOOP 0的方法,由于是循环0次,故在OP循环层次上若有LOOP为0的情况,则也可以省略该操作,原因很明显:若镶嵌层次上有一个为0,则表示该操作不能执行
另外介绍一下本题的难点:
1)如何正确累计相应幂次项?
方法:在计算每一个OP操作循环次数时,计数因子中n的个数为num,然后将数字联乘,那么该数字就因该为幂num的项(还需要累加,才能得到最后的项数)
2) 处理LOOP循环是难点。如何处理为n和为数字的两种不同情况?
方法:分别处理为n和数字的情况,其中为数字的情况比较复杂,要另外添加辅助数组记录数字的每一位,然后还原,最后由于是连续接受输入,所以需要另外的输入处理,以便下一次循环正确。
下面是代码:156K+0MS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define Max 20 //最大层次为10次,取大
int mi[Max]; //记录幂为i的项数
struct Node{ //记录镶嵌层次上各层次的状态
bool word; //判断是否为字符n
int value;//若是数字记录该数字
}node[Max]; //最大镶嵌层次为10,取大
char Input[Max]; //辅助数组,记录输入的整形
int n; //case数目
int main(){
scanf("%d",&n);
for(int k=1;k<=n;k++){
memset(mi,0,sizeof(mi)); //初始化为项数全0
int pivot=-1; //初始化下标为-1
char temp;
bool right=true; // 标记是否是LOOP的对数字的特殊处理
while(true){ //循环,处理输入
if(right){ //若不是LOOP对数字的特殊处理
temp=getchar(); //接受无效输入
while(temp==' ' || temp=='\n')
temp=getchar();
}
right=true; //若为LOOP对数字的特殊处理,则直接跳到判断类型,但是需要将值取反,因为那是上一次的输入
if(temp=='B'){ // 若为BEGIN,则再连续接受4个输入,然后循环
getchar();
getchar();
getchar();
getchar();
}
else if(temp=='L'){ //若为LOOP则记录循环镶嵌层次
getchar(); //连续接受LOOP字符
getchar();
getchar();
temp=getchar();
while(temp==' ' || temp=='\n') // 接受无效输入
temp=getchar();
if(temp=='n') //若为字符n则设置标记为true,下一次输入正常处理
node[++pivot].word=true;
else{ //否则处理数字输入
node[++pivot].word=false; //标记为数字
int index=0; //下标初始化为0
Input[index++]=temp;//存储数字最高位
temp=getchar();
while(temp>='0' && temp<='9'){ //连续输入数字的低位部分
Input[index++]=temp;
temp=getchar();
}
right=false; //标记下一次循环直接判断即可,无需接受无效输入
while(temp==' ' || temp=='\n') //找到第一个有效字符,作为下一次的判别处理
temp=getchar();
int vv=1; //各位为权值1
int Sum=0; //初始化为0
for(int s=index-1;s>=0;s--){ // 从低位到高位转化为整数
Sum+=(vv*(Input[s]-'0'));
vv*=10;
}
node[pivot].value=Sum; //存储数字
}
}
else if(temp=='O'){ //若为OP 操作
getchar();
int num=0,Sum=0,v;
scanf("%d",&v); //输入数字
if(v==0) //若为0,则可省略该操作
continue;
Sum+=v; //否则初始化为该数字
bool trag=true; //标记镶嵌循环层次上是否存在循环次数为0的情况
for(int i=0;i<=pivot;i++){
if(!node[i].word && node[i].value==0){ //若存在为0情况
trag=false;
break;
}
if(!node[i].word && node[i].value>0) //若为数字,则连乘
Sum*=node[i].value;
else if(node[i].word) //若为字符‘n'则累加,判断幂指数
num++;
}
if(trag) // 若不再任何循环内,或者循环层次上没有次数为0的情况
mi[num]+=Sum; //累加相应幂次项的项数
}
else if(temp=='E'){ //若为END,则要递减循环镶嵌层次
getchar();
getchar();
if(pivot<0) //若为与开头BEGIN对应的END则要退出循环,该case结束,处理结束
break;
pivot--;
}
}
printf("Program #%d\nRuntime = ",k); //处理输出
int i;
bool flag=false; //标记1——10幂指数项数是否有大于0的情况,找出第一个幂次项数大于0的幂指数,第一个项不用输出'+'符号
for(i=10;i>=1;i--){
if(mi[i]>1){ //若存在大于1的情况
flag=true;
if(i>1)
printf("%d*n^%d",mi[i],i); //可输出项数和幂指数
else
printf("%d*n",mi[i]); //只可输出幂指数,项数为1,不能输出
break;
}
else if(mi[i]==1 && i==1){ //同理
flag=true;
printf("n");
break;
}
else if(mi[i]==1 && i!=1){ //同理
flag=true;
printf("n^%d",i);
break;
}
}
if(!flag){ //若1——10都不存在项数大于0的幂指数,则检查最后的0次幂
if(mi[0]>0) //若大于0,则直接输出,不用加'+'
printf("%d\n\n",mi[0]);
else
printf("0\n\n"); //否则为0
continue;
}
for(int j=i-1;j>=1;j--){ //若1——10存在项数大于0的幂指数,则依次输出后续项数大于0的幂指数,注意要加’+‘
if(mi[j]>1){
if(j>1)
printf("+%d*n^%d",mi[j],j);
else
printf("+%d*n",mi[j]);
}
else if(mi[j]==1 && j==1){
printf("+n");
}
else if(mi[j]==1 && j!=1){
printf("+n^%d",j);
}
}
if(mi[0]>0) //检查0次幂,若大于0则直接输出,否则输出空行(2个)
printf("+%d\n\n",mi[0]);
else
printf("\n\n");
}
return 0;
}