2017计蒜之道 初赛 第二场 百度的科学计算器(简单)
/** 题目:2017计蒜之道 初赛 第二场 百度的科学计算器(简单) 链接:https://nanti.jisuanke.com/t/15504 题意:给一个合法的表达式,包含加号+、减号-、括号()、数字常量,表达式中没有空格。 输入数据保证数字常量以及计算过程中数值绝对值均不超过 10^12,对于浮点型数值常量,保证小数点后不超过 6位。 思路:暴力模拟;python有函数可以直接调用。 坑点:如果表达式中出现过浮点数,那么输出结果保留6位小数, 否则输出整数,不出现小数。 */ #include <iostream> #include <cstdio> #include <vector> #include <cstring> #include <cmath> #include <algorithm> using namespace std; typedef long long LL; const int mod=1e9+7; const int maxn=1e6+5; const double eps = 1e-12; char op[1005]; double a[1004]; char s[1004]; int n; int flag; int main() { while(scanf("%d",&n)==1) { scanf("%s",s); flag = 0; int az = 0, pz = 0; int len = strlen(s); for(int i = 0; i < len; ){ LL in = 0; LL dt = 0; LL p = 1; if(s[i]>='0'&&s[i]<='9'){ while(i<len&&s[i]>='0'&&s[i]<='9'){ in = in*10+(s[i]-'0'); i++; } if(s[i]=='.'){ flag = 1; i++; while(i<len&&s[i]>='0'&&s[i]<='9'){ dt = dt*10+(s[i]-'0'); i++; p *= 10; } } double x = in+1.0*dt/p; a[az++] = x; }else { if(s[i]=='-'){ op[pz++] = '-'; i++; continue; } if(s[i]=='+'){ i++; op[pz++] = '+'; continue; } if(s[i]=='('){ i++; op[pz++] = '('; continue; } if(s[i]==')'){///左结合。找到左边的符号,以及左边的数,然后模拟计算过去。 int pl = pz-1; while(op[pl]!='(') pl--; int temp = pl;// pz = tmep; int cnt = pz-pl-1; int tempa = az-cnt-1; double value = a[az-cnt-1]; for(int j = pl+1, k = az-cnt; j < pz; j++,k++){ if(op[j]=='+'){ value += a[k]; }else value -= a[k]; } pz = temp; az = tempa; a[az++] = value; i++; continue; } } } double value = a[0];///已处理所有括号,只有数和-,+符号。左结合计算。 for(int j = 0, k = 1; j < pz; j++,k++){ if(op[j]=='+'){ value += a[k]; }else value -= a[k]; } if(flag)///如果出现过浮点数。 printf("%.6lf\n",value); else printf("%lld\n",(LL)value); } return 0; }
表达式树解法:可处理加减乘除都出现的情况。
思路:每次把最后进行的计算符号作为根。递归处理。
#include <iostream> #include <cstdio> #include <vector> #include <cstring> #include <cmath> #include <algorithm> using namespace std; typedef long long LL; const int mod=1e9+7; const int maxn=1e3+5; const double eps = 1e-12; int lch[maxn], rch[maxn]; struct node { double value; char op; }t[maxn]; int nc = 0; char s[maxn]; int isDouble; int build_tree(char *s,int x,int y)///[x, y) { int c1 = -1, c2 = -1, p = 0; int u; int sign = 0; for(int i = x; i < y; i++){ switch(s[i]){ case '(': p++; sign = 1;break; case ')': p--; sign = 1;break; case '+': case '-': if(!p) c1 = i; sign = 1;break;///括号外的最后计算的+,-符号。 case '*': case '/': if(!p) c2 = i; sign = 1;break;///括号外的最后计算的*,/符号。 } } if(sign==0){///全是数字或者小数点。说明已经是叶子了。 double in = 0; LL dt = 0; LL p = 1; while(x<y&&s[x]!='.'){ in = in*10 + (s[x]-'0'); x++; } if(x<y&&s[x]=='.'){ x++; isDouble = 1; while(x<y){ dt = dt*10 + (s[x]-'0'); x++; p = p*10; } } u = ++nc; t[u].value = in+1.0*dt/p; lch[u] = 0; rch[u] = 0; return u; } if(c1<0) c1 = c2;///没有加减符号. if(c1<0) return build_tree(s,x+1,y-1); ///没有乘除符号,那么应该是被括号包含,去掉两边的括号。 u = ++nc; lch[u] = build_tree(s,x,c1); rch[u] = build_tree(s,c1+1,y); t[u].op = s[c1]; return u; } double dfs(int root) { if(lch[root]==0&&rch[root]==0){ return t[root].value; } char op = t[root].op; double lans = dfs(lch[root]), rans = dfs(rch[root]); switch(op){ case '+': return lans+rans; case '-': return lans-rans; case '*': return lans*rans; case '/': return lans/rans; } return -1; } int main() { int n; while(scanf("%d",&n)==1) { scanf("%s",s); nc = 0; isDouble = 0; int root = build_tree(s,0,strlen(s));/// root=1 double ans = dfs(root); if(isDouble) printf("%.6lf\n",ans);///出现浮点数,输出6位小数,否则输出整数。 else printf("%lld\n",LL(ans)); } return 0; }
posted on 2017-05-22 11:03 hnust_accqx 阅读(212) 评论(0) 编辑 收藏 举报