软工第二次作业
GIT地址 | https://github.com/Cpu8285 |
GIT名称 | Cpu8285 |
学号后五位 | 64222 |
博客地址 | https://www.cnblogs.com/565118008a/ |
作业地址 | https://www.cnblogs.com/ChildishChange/p/10398212.htm |
1.配置环境
试了很多钟方法,VS2017无法安装,可能我的电脑不适配,然后改下VS2015,居然这么久,惊了。。。
2.代码
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 mt19937 mt(time(0)); // 随机数生成器 6 7 map<int, char> op; // 运算符id及其符号映射 8 map<int, int> pri; // 运算符id及其优先级映射 9 // 10表示加号 运算优先级为 0 10 // 11表示减号 运算优先级为 0 11 // 12表示乘号 运算优先级为 1 12 // 13表示除号 运算优先级为 1 13 // 14表示左括号 运算优先级为 2 14 // 15表示右括号 运算优先级为 2 15 16 // 运算数结构体,id为运算数的位置,val为运算数的值 17 struct node{ 18 int id, val; 19 node(int id = -1, int val = -1):id(id), val(val){} 20 }; 21 22 // tot:逆波兰表达式的长度,operatorNum:运算符个数 23 // operandNum:运算数的个数,bracketNum:括号对数,ans:运算式最终答案 24 // hasBracket:某个数字处是否有括号,-1表示无括号,14表示左括号,15表示右括号 25 // operators:对应位置的运算符种类 operands:表示对应位置运算数的值 26 // RPN:存储逆波兰表达式 fac:存储某个数的约数 27 // opr:中缀表达式转后缀表达式时的运算符栈 28 // opd:中缀表达式转后缀表达式时的运算数栈 29 30 int tot, operatorNum, operandNum, bracketNum, ans; 31 int hasBracket[15], operators[15], operands[15]; 32 int RPN[55], fac[105]; 33 stack<int> opr; 34 stack<node> opd; 35 36 // 初始化函数零:初始化运算符 id 符号 以及运算优先级,并且重定向输出 37 void init0(){ 38 op[10] = '+', op[11] = '-'; 39 op[12] = '*'; 40 op[14] = '(', op[15] = ')'; 41 pri[10] = 0, pri[11] = 0; 42 pri[12] = 1, pri[13] = 1; 43 pri[14] = 2, pri[15] = 2; 44 freopen("../result.txt", "w", stdout); 45 } 46 47 // 初始化函数一:在每次调用solve()时进行初始化 48 void init1(){ 49 tot = 0; 50 for(int i = 0; i < 15; ++i){ 51 operators[i] = -1; 52 operands[i] = -1; 53 hasBracket[i] = -1; 54 } 55 while(!opr.empty()) opr.pop(); 56 while(!opd.empty()) opd.pop(); 57 } 58 59 // 初始化函数二:在每次调用getOperands()时进行初始化 60 void init2(){ 61 tot = 0; 62 while(!opr.empty()) opr.pop(); 63 while(!opd.empty()) opd.pop(); 64 } 65 66 // 获取运算数的值的函数,如果返回 true 则表示获取成功,否则表示获取失败 67 bool getOperands(){ 68 init2(); 69 // 将中缀表达式转换成后缀表达式(也就是逆波兰表达式) 70 if(hasBracket[0] != -1) opr.push(hasBracket[0]); 71 RPN[tot++] = 0; 72 for(int i = 1; i < operandNum; ++i){ 73 while(true){ 74 if(opr.empty() || opr.top() == 14 || pri[operators[i - 1]] > pri[opr.top()]){ 75 opr.push(operators[i - 1]); 76 break; 77 } 78 RPN[tot++] = opr.top(); 79 opr.pop(); 80 } 81 if(hasBracket[i] == 14){ 82 opr.push(hasBracket[i]); 83 } 84 RPN[tot++] = i; 85 if(hasBracket[i] == 15){ 86 while(opr.top() != 14){ 87 RPN[tot++] = opr.top(); 88 opr.pop(); 89 } 90 opr.pop(); 91 } 92 } 93 while(!opr.empty()){ 94 RPN[tot++] = opr.top(); 95 opr.pop(); 96 } 97 // 转换成逆波兰表达式后便可以进行尝试填数 98 for(int i = 0; i < tot; ++i){ 99 // 如果为运算数则随机为其赋值 100 if(RPN[i] < 10){ 101 int x = mt()%66 + 1; 102 operands[RPN[i]] = x; 103 opd.push(node(RPN[i], x)); 104 continue; 105 } 106 //如果为除法,要将除数随机分配为被除数的一个因子 107 //如果为减法,要注意减数不能大于被减数 108 109 if(RPN[i] == 13){ 110 node b = opd.top(); opd.pop(); 111 node a = opd.top(); opd.pop(); 112 if(a.val%b.val == 0){ 113 opd.push(node(-1, a.val/b.val)); 114 continue; 115 } 116 if(b.id == -1) return false; 117 int cnt = 0; 118 for(int j = 1; j <= a.val; ++j){ 119 if(j >= 100) break; 120 if(a.val%j) continue; 121 fac[cnt++] = j; 122 } 123 int x = mt()%cnt; 124 operands[b.id] = fac[x]; 125 opd.push(node(-1, a.val/fac[x])); 126 }else if(RPN[i] == 11){ 127 node b = opd.top(); opd.pop(); 128 node a = opd.top(); opd.pop(); 129 int dt = a.val - b.val; 130 if(dt <= 0) return false; 131 opd.push(node(-1, dt)); 132 }else{ 133 node b = opd.top(); opd.pop(); 134 node a = opd.top(); opd.pop(); 135 if(RPN[i] == 10) opd.push(node(-1, a.val + b.val)); 136 if(RPN[i] == 12) opd.push(node(-1, a.val*b.val)); 137 } 138 } 139 ans = opd.top().val; opd.pop(); 140 //控制最终运算结果的范围,可根据需要进行调节 141 if(ans < 0 || ans > 1000) return false; 142 return true; 143 } 144 145 bool solve(){ 146 init1(); 147 // 随机生成运算符的个数 3~5 ,及运算数个数 4~6 148 operatorNum = mt()%3 + 3; 149 operandNum = operatorNum + 1; 150 // 随机生成括号个数 151 bracketNum = min((int)(operandNum/2), (int)(mt()%3 + 2)); 152 // 随机生成运算符的种类 153 for(int i = 0; i < operatorNum; ++i) operators[i] = mt()%4 + 10; 154 // 随机生成括号位置 155 for(int i = 0; i < bracketNum*2; ++i){ 156 int x = mt()%operandNum; 157 while(hasBracket[x] != -1) x = mt()%operandNum; 158 hasBracket[x] = 0; 159 } 160 161 // 根据相对位置确定括号为左括号还是右括号 162 bool lf = true; 163 for(int i = 0; i < operandNum; ++i){ 164 if(hasBracket[i] == -1) continue; 165 if(lf) hasBracket[i] = 14; 166 else hasBracket[i] = 15; 167 lf = (!lf); 168 } 169 170 // 到这里已经将等式预处理成了(a+b)/c*(d-e)的类似形式 171 // 预处理结束之后,我们就要尝试将 a b c d e 确定为具体的数 172 if(!getOperands()) return false; 173 174 // 在获取完运算数之后,便可以输出我们得到的等式了 175 if(hasBracket[0] != -1) printf("("); 176 printf("%d", operands[0]); 177 for(int i = 1; i < operandNum; ++i){ 178 if(operators[i - 1] == 13) printf("÷"); 179 else printf("%c", op[operators[i - 1]]); 180 if(hasBracket[i] == 14) printf("("); 181 printf("%d", operands[i]); 182 if(hasBracket[i] == 15) printf(")"); 183 } 184 printf("=%d\n", ans); 185 return true; 186 } 187 188 189 int main(){ 190 // 初始化函数零:初始化运算符 id 符号 以及运算优先级,并且重定向输出 191 init0(); 192 //读入需要生成的运算式数量 193 int n; 197 while(n--) while(!solve()) ; 198 199 return 0; 200 }
3.GIT软件上传GITHUB,VS2017无法下载,所以暂时无从下手。
4·感想
完成质量有点差,早上八点到晚上九点一直再赶,到后面只是把代码研究了出来,其他根本无从下手,
融入新事物的能力差,已经养成依赖老师讲解的思维,到自己做的时候就无所适从,这是我的一个很大
问题。