http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1145
题目大意:
一种只有三种运算符的运算:加减乘,而且运算没有优先规则:他们知识严格的将没想数据从左边计算到右边。例如:3+3*5,他们的计算结果是30,而不是18
编程要求:
对于输入的等式,将等号右边的数据之间加上运算符,使其计算结果为等号左边的数,然后输出添加运算符后的等式,如果不能求得满足要求等式,输出“Impossible”,每组数据后输出一个空行。
算法分析:
对于此题,要解决的主要问题有:1、构造表达式 2、求解构造的表达式的值
由于此题求解过程中需要多次遍历表达式,所以如果将表达式存储起来程序运行起来就回快很多,具体就是转化为伪表达式,将括号进行整数化标记,按照整数数据存储起来,并将需要插入运算符的位置记录下来,这样每次只需在需要插入运算符的位置上dfs插入运算符,然后递归求表达式的值就行了。
具体:用数组b[]存放伪表达式,op[]存放运算符在数组中的位置,ansx[]存放运算符
View Code
#include<iostream> #include<cstdio> #include<cstring> using namespace std; #define LEFT -1 //左括号 #define RIGHT -2 //右括号 #define MUL -3 //*号 #define ADD -4 //+号 #define SUB -5 //-号 #define OP -6 //有运算符 #define NONE -10 int ans,flag; int b[100], //伪表达式 op[50], //运算符在数组b中的位置 bn, //数组b的项数 ansx[15],//答案,存放的为运算符 ipos,bpos,opos; char str[100]; char pop[] = " ()*+-?"; int compute(); int bracket() { int sum; if(b[bpos] == LEFT) { ++ bpos; //跳过左括号 sum = compute(); //计算括号里面的值 ++ bpos; //跳过右括号 } else sum = b[bpos++]; //没有括号 return sum; } int compute() //求解表达式的值 { int sum = bracket(); //取出第一个数 while(b[bpos] == MUL || b[bpos] == ADD || b[bpos] == SUB) { int operation = b[bpos++]; //取出运算符 int ret = bracket(); //取出下一个数 switch(operation) { case MUL: sum *= ret; break; case ADD: sum += ret; break; case SUB: sum -= ret; break; } } return sum; } void dfs(int t) //dfs插入运算符,求解表达式, { if(flag) return ; int i; if(t == opos) //运算符插入完毕,计算表达式的值 { bpos = 0; int tmp = compute(); //计算右边等式的值 if(tmp == ans) { flag = 1; for(i = 0; i < bn; ++ i) ansx[i] = b[i]; } return ; } b[op[t]] = MUL; dfs(t+1); b[op[t]] = ADD; dfs(t+1); b[op[t]] = SUB; dfs(t+1); } void print(int q[]) //打印表达式 { printf("%d=",ans); int i; for(i = 0; i < bn; ++ i) { if(q[i] >= -6 && q[i] <= -1) putchar(pop[-q[i]]); else printf("%d",q[i]); } } void space() //跳过空格 { while(str[ipos] && str[ipos] == ' ') ++ ipos; } int main() { int test = 1; while(gets(str) && strchr(str,'=') && strcmp(str,"0") != 0) { for(int i = 0; i < 100; ++ i) b[i] = NONE; sscanf(str,"%d[^ =]",&ans); for(ipos = 0; str[ipos] != '='; ++ ipos); ++ ipos; bn = 0; opos = 0; while(space(),str[ipos]) //转化为伪表达式 { if(str[ipos] == '(') //左右括号 { b[bn++] = LEFT,++ ipos; continue; } else if(str[ipos] == ')') b[bn++] = RIGHT,++ ipos; else { sscanf(str + ipos,"%d[^ ()]",&b[bn++]); //保存整数数据 while(str[ipos] && isdigit(str[ipos])) ++ipos; } space(); if(str[ipos] && str[ipos] != ')') //如果不是结尾和‘)’,则有一个运算符 { op[opos++] = bn; //记录运算符的位置 b[bn++] = OP; } } flag = 0; dfs(0); printf("Equation #%d:\n",test ++); if(!flag) printf("Impossible"); else { print(ansx); } printf("\n\n"); } return 0; } /* 18 = 7 (5 3) 2 30 = 3 3 5 18 = 3 3 5 5 = 3 3 12 = 2 2 2 2 2 2 */