在某些应用中,为了支持灵活性,往往用到自定义的公式。
比如,有如下的原始公式集合:
int add(int x, int y): 返回x与y的和
int add(int x, int y, int z): 返回x,y,z三个数的和
int min(int x, int y): 返回x,y中较小的值
int max(int x, int y): 返回x,y中较大的值
int doubleMe(int x): 返回 x 的2倍
给出一个自定义公式串
add(min(5,3),max(2,8),add(1,doubleMe(1)))
通过手工计算可以得出结果为:14
本题的任务是:编写一个解析程序,能够对由上述原始公式任意组合出来的公式计算其结果。也就是输入一个自定义公式串,输出它的计算结果(可以不考虑输入公式本身有语法错误的情况)。
输入的公式串中可以含有多余的空格,类似:
add( min(5, 3) , max(2 , 8) ) 也是合法的公式。
程序输入:公式串
程序输出:该公式的计算值
解题思路:思路相对来说比较简单,以前做过好几道这样的题目,但是这是第一次完全自己写的,其实就是用递归的思路,不过要做递归,思路一定是需要清晰的,否则在递归的时候很容易出错,并且出了错还是不好查找的,另外的一个重要的事情就是必须要设定好正确的递归出口,深切体验。。。
具体思路,在每一次的时候都是从第一个字母开始搜索,当遇到关键的字眼,也就是add、min、max、doubleMe的时候就就开始分割,直到出现的左括号‘(’的数目和右括号‘)’的数目相同,并且出现了部分的结束标志,也就是再一个’)‘或者是’,‘,这样的话就把每一部分分解开了,但是这样的话代码好像就不太美观了,有点长。。。
#include <iostream> #include <cstdio> #include <memory.h> using namespace std; int count(string str){ int len = str.length(); if(str[0]<='9'&&str[0]>='0'){ int temp=0,i=0; temp=str[i++]-'0'; while(i<len&&str[i]<='9'&&str[i]>='0'){ temp=temp*10+str[i]-'0'; i++; } return temp; } if(str[0]=='a'){ int i=4,templ=0,tempr=0,tmp=0; for(int x=1;x<=3&&i<len;x++,i++){ string s=""; while( templ!=tempr|| ( str[i]!=',' && str[i]!=')' ) ){ if(str[i]=='(') templ++; if(str[i]==')') tempr++; s+=str[i]; i++; } tmp+=count(s); } return tmp; } if(str[0]=='m'&&str[1]=='i'){ int i=4,templ=0,tempr=0,tmp1=0,tmp2=0; for(int x=1;x<=2&&i<len;x++,i++){ string s=""; while( templ!=tempr|| ( str[i]!=',' && str[i]!=')' ) ){ if(str[i]=='(') templ++; if(str[i]==')') tempr++; s+=str[i]; i++; } x==1?tmp1=count(s):tmp2=count(s); } return tmp1<tmp2?tmp1:tmp2; } if(str[0]=='m'&&str[1]=='a'){ int i=4,templ=0,tempr=0,tmp1=0,tmp2=0; for(int x=1;x<=2&&i<len;x++,i++){ string s=""; while( templ!=tempr|| ( str[i]!=',' && str[i]!=')' ) ){ if(str[i]=='(') templ++; if(str[i]==')') tempr++; s+=str[i]; i++; } x==1?tmp1=count(s):tmp2=count(s); } return tmp1>tmp2?tmp1:tmp2; } if(str[0]=='d'){ int i=9,templ=0,tempr=0; string s=""; while( templ!=tempr|| ( str[i]!=',' && str[i]!=')' ) ){ if(str[i]=='(') templ++; if(str[i]==')') tempr++; s+=str[i]; i++; } return count(s)*2; } return 0; } int main() { string str; char ch='\n'; while(ch=='\n'){ str=""; while(~scanf("%c",&ch)&&ch!='\n') if(ch!=' ') str+=ch; int len = str.length(); cout<<count(str)<<endl; } return 0; }
稍微修改了一下,这样好像美观一点,但是换汤不换药,只是函数更加明确了点。。。
#include <iostream> #include <cstdio> #include <memory.h> using namespace std; string s;//记录当前切割出的子串 int cut(string str,int i){ //返回当前已经搜索完了的str的i的下一个位置 s=""; int templ=0,tempr=0; while( templ!=tempr|| ( str[i]!=',' && str[i]!=')' ) ){ if(str[i]=='(') templ++; if(str[i]==')') tempr++; s+=str[i]; i++; } return i+1; } int count(string str){ int len = str.length(); int tmp1=0,tmp2=0,temp=0,tmp=0; //tmp1,tmp2比较大小时记录两个数 temp记录返回数的时候的值, tmp记录求和的时候的和 if(str[0]<='9'&&str[0]>='0'){ int i=0; //记录遍历的起始位置 temp=str[i++]-'0'; while(i<len&&str[i]<='9'&&str[i]>='0'){ temp=temp*10+str[i]-'0'; i++; } return temp; } if(str[0]=='a'){//实现add()函数 int i=4; for(int x=1;x<=3&&i<len;x++){//注意需要用Len来控制add()函数是双目还是三目运算符 i=cut(str,i); tmp+=count(s); } return tmp; } if(str[0]=='m'){//实现min()、max()函数 int i=4; for(int x=1;x<=2;x++){ i=cut(str,i); x==1?tmp1=count(s):tmp2=count(s); } if(str[1]=='i') return tmp1<tmp2?tmp1:tmp2;//返回最小值 return tmp1>tmp2?tmp1:tmp2;//返回最大值 } if(str[0]=='d'){//doubleMe()函数 int i=9; i=cut(str,i); return count(s)*2; } return 0; } int main() { string str=""; char ch; while(~scanf("%c",&ch)&&ch!='\n') if(ch!=' ') str+=ch; cout<<count(str); return 0; }