1 任务描述
1.1 概述
使用java或C/C++编程语言,独立完成一个3到5个运算符的四则运算练习的软件
1.2 基本要求
-
1 程序可接收一个输入参数n,然后随机产生n道加减乘除(分别使用符号±*÷来表示)练习题,每个数字在 0 和 100 之间,运算符在3个到5个之间。
-
2 每个练习题至少要包含2种运算符。同时,由于小学生没有分数与负数的概念,你所出的练习题在运算过程中不得出现负数与非整数,比如不能出 3÷5+2=2.6,2-5+10=7等算式。
-
3 练习题生成好后,将你的学号与生成的n道练习题及其对应的正确答案输出到文件“result.txt”中,不要输出额外信息,文件目录与程序目录一致。
-
4 当程序接收的参数为4时,以下为一个输出文件示例。
2018010203 13+17-1=29 11*15-5=160 3+10+4-16=1 15÷5+3-2=4
1.3 附加功能要求
-
1 支持有括号的运算式,包括出题与求解正确答案。注意,算式中存在的括号数必须大于2对,且不得超过运算符的个数。
-
2 扩展程序功能支持真分数的出题与运算(只需要涵盖加减法即可),例如:1/6 + 1/8 + 2/3= 23/24。注意在实现本功能时,需支持运算时分数的自动化简,比如 1/2+1/6=2/3,而非4/6,且计算过程中与结果都须为真分数。
2 项目地址
个人博客
https://linxi99.gitee.io/20190319/Arithmetic-Device/
https://blog.youkuaiyun.com/linxilinxilinxi
https://blog.youkuaiyun.com/linxilinxilinxi/article/details/88548481
项目地址
https://gitee.com/linxi99/four_operational_generators
3 项目源代码
#include <bits/stdc++.h>
using namespace std;
mt19937 mt(time(0));
map<int, char> op;
map<int, int> pri;
struct node{
int id, val;
node(int id = -1, int val = -1):id(id), val(val){
}
};
int tot, operatorNum, operandNum, bracketNum, ans;
int hasBracket[15], operators[15], operands[15];
int RPN[55], fac[105];
stack<int> opr;
stack<node> opd;
void init1(){
tot = 0;
for(int i = 0; i < 15; ++i){
operators[i] = -1;
operands[i] = -1;
hasBracket[i] = -1;
}
while(!opr.empty()) opr.pop();
while(!opd.empty()) opd.pop();
}
void init2(){
tot = 0;
while(!opr.empty()) opr.pop();
while(!opd.empty()) opd.pop();
}
bool getOperands(){
init2();
if(hasBracket[0] != -1) opr.push(hasBracket[0]);
RPN[tot++] = 0;
// puts("**3.1**");
for(int i = 1; i < operandNum; ++i){
// printf("%d\n", i);
while(true){
if(opr.empty() || opr.top() == 14 || pri[operators[i - 1]] > pri[opr.top()]){
opr.push(operators[i - 1]);
break;
}
RPN[tot++] = opr.top();
opr.pop();
}
if(hasBracket[i] == 14){
opr.push(hasBracket[i]);
}
RPN[tot++] = i;
if(hasBracket[i] == 15){
while(opr.top() != 14){
RPN[tot++] = opr.top();
opr.pop();
}
opr.pop();
}
}
// puts("**3.2**");
while(!opr.empty()){
RPN[tot++] = opr.top();
opr.pop();
}
// for(int i = 0; i < tot; ++i){
// printf("%d ", RPN[i]);
// }
// puts("");
// puts("**3.3**");
for(int i = 0; i < tot; ++i){
if(RPN[i] < 10){
int x = mt()%66 + 1;
operands[RPN[i]] = x;
opd.push(node(RPN[i], x));
continue;
}
if(RPN[i] == 13){
node b = opd.top(); opd.pop();
node a = opd.top(); opd.pop();
if(a.val%b.val == 0){
opd.push(node(-1, a.val/b.val));
continue;
}
if(b.id == -1) return false;
int cnt = 0;
for(int j = 1; j <= a.val; ++j){
if(a.val%j) continue;
fac[cnt++] = j;
}
int x = mt()%cnt;
operands[b.id] = fac[x];
opd.push(node(-1, a.val/fac[x]));
}else if(RPN[i] == 11){
node b = opd.top(); opd.pop();
node a = opd.top(); opd.pop();
int dt = a.val - b.val;
if(dt <= 0) return false;
opd.push(node(-1, dt));
}else{
node b = opd.top(); opd.pop();
node a = opd.top(); opd.pop();
if(RPN[i] == 10) opd.push(node(-1, a.val + b.val));
if(RPN[i] == 12) opd.push(node(-1, a.val*b.val));
}
}
// puts("**3.4**");
ans = opd.top().val; opd.pop();
if(ans < 0 || ans > 1000) return false;
// for(int i = 0; i < tot; ++i){
// printf("%d ", RPN[i]);
// }
// puts("");
return true;
}
bool solve(){
init1();
operatorNum = mt()%3 + 3;
operandNum = operatorNum + 1;
bracketNum = min((int)(operandNum/2), (int)(mt()%2 + 2));
// printf("%d %d %d\n", operatorNum, operandNum, bracketNum);
for(int i = 0; i < operatorNum; ++i) operators[i] = mt()%4 + 10;
for(int i = 0; i < bracketNum*2; ++i){
int x = mt()%operandNum;
while(hasBracket[x] != -1) x = mt()%operandNum;
hasBracket[x] = 0;
}
// puts("**1**");
bool lf = true;
for(int i = 1; i < operandNum; ++i){
if(operators[i - 1] == 13){
if(hasBracket[i] == 14){
for(int j = 0; j < 15; ++j) hasBracket[j] = -1;
break;
}
if(i < operandNum - 1 && operators[i] >= 12) return false;
}
}
// puts("**2**");
for(int i = 0; i < operandNum; ++i){
if(hasBracket[i] == -1) continue;
if(lf) hasBracket[i] = 14;
else hasBracket[i] = 15;
lf = (!lf);
}
// puts("**3**");
if(!getOperands()) return false;
// puts("**4**");
if(hasBracket[0] != -1) printf("(");
printf("%d", operands[0]);
for(int i = 1; i < operandNum; ++i){
if(operators[i - 1] == 13) printf("");
else printf("%c", op[operators[i - 1]]);
if(hasBracket[i] == 14) printf("(");
printf("%d", operands[i]);
if(hasBracket[i] == 15) printf(")");
}
printf("=%d\n", ans);
return true;
}
int main(){
op[10] = '+', op[11] = '-';
op[12] = '*';
op[14] = '(', op[15] = ')';
pri[10] = 0, pri[11] = 0;
pri[12] = 1, pri[13] = 1;
pri[14] = 2, pri[15] = 2;
freopen("../result.txt","w",stdout);
int n;
scanf("%d", &n);
puts("2017012449");
while(n--) while(!solve());
return 0;
}
4 更新版本
4.1 源代码 2.0
#include <bits/stdc++.h>
using namespace std;
mt19937 mt(time(0)); // 随机数生成器
map<int, char> op; // 运算符id及其符号映射
map<int, int> pri; // 运算符id及其优先级映射
// 10表示加号 运算优先级为 0
// 11表示减号 运算优先级为 0
// 12表示乘号 运算优先级为 1
// 13表示除号 运算优先级为 1
// 14表示左括号 运算优先级为 2
// 15表示右括号 运算优先级为 2
// 运算数结构体,id为运算数的位置,val为运算数的值
struct node{
int id, val;
node(int id = -1, int val = -1):id(id), val(val){
}
};
// tot:逆波兰表达式的长度,operatorNum:运算符个数
// operandNum:运算数的个数,bracketNum:括号对数,ans:运算式最终答案
// hasBracket:某个数字处是否有括号,-1表示无括号,14表示左括号,15表示右括号
// operators:对应位置的运算符种类 operands:表示对应位置运算数的值
// RPN:存储逆波兰表达式 fac:存储某个数的约数
// opr:中缀表达式转后缀表达式时的运算符栈
// opd:中缀表达式转后缀表达式时的运算数栈
int tot, operatorNum, operandNum, bracketNum, ans;
int hasBracket[15], operators[15], operands[15];
int RPN[55], fac[105];
stack<int> opr;
stack<node> opd;
// 初始化函数零:初始化运算符 id 符号 以及运算优先级,并且重定向输出
void init0(){
op[10] = '+', op[11] = '-';
op[12] = '*';
op[14] = '(', op[15] = ')'