poj1472

12 篇文章 0 订阅
6 篇文章 0 订阅

题目较复杂。模拟+字符串处理

大致题意为:给定一个特定程序,有如下语句组成:

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;
}


 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值