# 小学生数学算式自动出题器

4 篇文章 0 订阅

• 随机出现四个运算符
• 每次出现1-2运算符，计算式子a op b op c
• 按照优先级的运算顺序不能出现负数，非整数，大于100 的数,要不他们可能遭不住

/*
Author:Janspiry
Number:
Title:
Tags:
*/
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
char sig[5]="-+/*";
int a,b,c,op1,op2;
int calc(int a,int b,int op){
switch(sig[op]){
case '/':
if(b==0||a%b)	return inf;//特判除法
return a/b;
case '*':
return a*b;
case '-':
// if(a<b) return inf;
return a-b;
default: return a+b;
}
}
void init(){//随机函数
a=rand()%101;
b=rand()%101;
c=rand()%101;
op1=rand()%4;
op2=rand()%4;
}
bool valid(int num){//判断合法
return num>=0&&num<=100;
}
int main()
{
#ifdef __DEBUG__
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
srand(time(0));
int ans1,ans2,ks=1;
while(1){
init();
ans1=calc(a,b,op1);
ans2=calc(b,c,op2);
if((op2>>1)>(op1>>1)){//比较优先级
if(!valid(ans2)||!valid(calc(a,ans2,op1)))continue;
}else{
if(!valid(ans1)||!valid(calc(ans1,c,op2)))continue;
}
printf("P%d %d%c%d%c%d\n",ks++,a,sig[op1],b,sig[op2],c);
if(ks==300){//输出300组
break;
}
}
return 0;
}


/*
Author:Janspiry
Number:
Title:
Tags:
*/
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <ctime>
using namespace std;
#define ll long long
#define ull unsigned long long
#define pi acos(-1)
const int inf=0x3f3f3f3f;
char sig[5]="+-*/";
char ans[20],tmp[20];
int a,b,c,op1,op2;
int calc(char *s){
int a,b,n=strlen(s);
for(int i=n;i>=0;i--){//按照优先级递归求值
if(s[i]=='+'){
s[i]='\0';
return calc(s)+calc(s+i+1);
}else if(s[i]=='-'){
s[i]='\0';
a=calc(s);
b=calc(s+i+1);
if(a>100||b>100||a<b){//判断减法合法性
return inf;
}
return a-b;
}
}
for(int i=n-1;i>=0;i--){
if(s[i]=='*'){
s[i]='\0';
a=calc(s);
b=calc(s+i+1);
if(a>100||b>100){
return inf;
}
return calc(s)*calc(s+i+1);
}else if(s[i]=='/'){
s[i]='\0';
a=calc(s);
b=calc(s+i+1);
if(a>100||b>100||a==0||b==0||a%b){//判断除法合法性
return inf;
}
return a/b;
}
}

return atoi(s);
}
void init(){
a=rand()%100+1;
b=rand()%100+1;
c=rand()%100+1;
op1=rand()%4;
op2=rand()%4;
}
bool valid(char *s){
int ans=calc(s);
return ans>=0&&ans<=100;
}
void multiop(){//是否允许单算法符
while(op1==op2){
op2=rand()%4;
}
}
int main()
{
#ifdef __DEBUG__
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
srand((unsigned int)time(0));
int ks=1;
while(1){
init();
multiop();
sprintf(ans,"%d%c%d%c%d",a,sig[op1],b,sig[op2],c);
strcpy(tmp,ans);
if(valid(ans)){
printf("P%d: %s\n",ks++,tmp);
if(ks==300){
break;
}
}
}
//printf("Time elapsed: %.3lf s\n",1.0*clock()/CLOCKS_PER_SEC);
return 0;
}


##### 更新
• 增加可视化界面与一些选择操作
• 增加括号运算符
• 优化小学生视角效果

0.随机得到要分解的答案98
1.随机一个运算符比如*，然后随机一个数字2，那么98=249。
2.随机分解49或者2（用vector实现），假设选择的数的49，重复步骤1，分解得到了7
7，现在vector里面还有7，7，2
3.重复步骤2，得到了7=1+6
4.最后的答案就是（1+6）*7*2，括号需要我们在进行递归生成字符串的同时的判断优先级加上去。

###### 头文件
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<time.h>
#include<string>
#include<string.h>
#include<string.h>
using namespace std;
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
Q_OBJECT

public:
Widget(QWidget *parent = nullptr);
~Widget();
public:
QString ans;
private:
Ui::Widget *ui;
private slots:
void on_print_clicked();
void on_copy_clicked();
private:
char sig[5]="+-*/";//运算符
bool vis[5];//哪些运算符可用
int fac[505];//除法因子
int rangel,ranger;//运算范围
int len;//选择操作符的个数

int col,col_cnt;//打印栏数要求
int ks;//打印组数
int unit_len;//单元长度
bool display_ans;//是否显示结果
struct node{
int op,lnum,rnum;//分解表达式用,返回a op b
};
struct Tree{
int sum,op,lc,rc;//节点代表的数，分解用的操作符，左右儿子节点编号
}tree[505<<2];
vector<int>vec;//随机节点用
private:
void init();//获得设置，按设置随机
int create_op();//随机运算符
node create_formula(int sum);//分解表达式
void rand_exp();//随机表达式
string get_exp(int now);//递归得到表达式
void Print(int root);//按格式打印
};
#endif // WIDGET_H


###### .c文件
#include "widget.h"
#include "ui_widget.h"
#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<time.h>
#include<string>
#include<string.h>
#include<string>
#include <QClipboard>
using namespace std;
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
}

Widget::~Widget()
{
delete ui;
}

void Widget::init(){
rangel=ui->rangel->value();//最小范围
ranger=ui->ranger->value();//最大范围
if(rangel>ranger){
swap(rangel,ranger);
}
col=ui->col->value();//栏数
ks=ui->ks->value();//组数
len=ui->len->value();//运算符个数
col_cnt=0;
//    memset(vis,0,sizeof(vis));
//运算符的合法性
vis[1]=ui->minus->checkState();
vis[2]=ui->mult->checkState();
vis[3]=ui->div->checkState();

unit_len=12*len;//控制格式用
display_ans=ui->display_ans->checkState();//是否输出结果
ans="";//最后的字符串
}
int Widget::create_op(){
int op=rand()%4;
while(!vis[op]){//判断运算符合法性并生成
op=rand()%4;
}
return op;
}
Widget::node Widget::create_formula(int sum){//进行数的分解
int op=create_op();
int lnum,rnum,tot=0;
switch(sig[op]){
case '+':
lnum=rand()%(sum+1);
rnum=sum-lnum;
break;
case '-':
lnum=rand()%(ranger-rangel+1)+rangel;
rnum=sum-lnum;
while(rnum<rangel||rnum>ranger||lnum<sum){
lnum=rand()%(ranger-rangel+1)+rangel;
rnum=lnum-sum;
}
break;
case '*':
for(int i=rangel;i*i<=ranger;i++)if(i&&sum%i==0){
fac[tot++]=i;
}
lnum=fac[rand()%tot];
rnum=sum/lnum;
break;
default:
if(sum==0){
lnum=0;
rnum=max(rand()%(ranger-rangel+1)+rangel,1);
}else{
rnum=max(1,rand()%(ranger/sum+1));
lnum=sum*rnum;
while(lnum<rangel||lnum>ranger){
rnum=max(1,rand()%(ranger/sum+1));
lnum=sum*rnum;
}
}
break;
}
return {op,lnum,rnum};
};
void Widget::rand_exp(){
int cnt=0,tot=1,idx=1;
int sum=rand()%(ranger-rangel+1)+rangel;
node nod;
vec.clear();
while(cnt<len){//利用vector进行随机的节点选择，进行数的分解
cnt++;
nod=create_formula(sum);
tree[idx]={sum,nod.op,tot+1,tot+2};
tree[++tot]={nod.lnum,0,0,0};
vec.push_back(tot);
tree[++tot]={nod.rnum,0,0,0};
vec.push_back(tot);

int r=rand()%vec.size();
idx=vec[r];
sum=tree[idx].sum;
vec.erase(vec.begin()+r);
}
}
string Widget::get_exp(int now){//打印
// string s;
int lc=tree[now].lc,rc=tree[now].rc,op=tree[now].op;
if(tree[now].lc&&tree[now].rc){
string l=get_exp(lc);//递归得到表达式
string r=get_exp(rc);
if(tree[lc].lc&&op/2>tree[lc].op/2){//优先级高加括号
l="("+l+")";
}
if(tree[rc].lc&&(op/2>tree[rc].op/2||op==1||op==3)){
r="("+r+")";
}
return l+sig[op]+r;//返回l op r
}else{
}
}
void Widget::Print(int root){
string s=get_exp(root);//递归得到表达式
int slen=s.length();
int tmpc=0;
for(int i=0;i<slen;i++){
if(s[i]=='*'){
tmpc+=4;
//           ans=ans+" * ";
ans=ans+" × ";
}else if(s[i]=='/'){
tmpc+=4;
//            ans=ans+" / ";
ans=ans+" ÷ ";
}else if(s[i]=='+'||s[i]=='-'){
tmpc+=3;
ans=ans+" "+s[i]+" ";
}else{
tmpc++;
ans=ans+s[i];
}
}
if(display_ans){//选择输出结果进行的操作
QString tmp=QString::number(tree[root].sum);
ans=ans+" = "+tmp;
tmpc+=tmp.length();
}
if(++col_cnt>=col){//栏数控制
col_cnt=0;
ans=ans+"\r\n";
}else{
while(tmpc++<unit_len){
ans=ans+" ";
}
}
}
void Widget::on_print_clicked(){
srand(time(0));
int ans_cnt=0;
init();
while(1){//多组随机
rand_exp();
Print(1);
if(++ans_cnt>=ks){
break;
}
}
ui->display_area->clear();
ui->display_area->setText(QString(ans));//设置输出
};
void Widget::on_copy_clicked(){//复制调用剪切板
QClipboard* clipboard = QApplication::clipboard();
clipboard->setText(ans);
if(clipboard->supportsSelection()==0){
ui->display_area->selectAll();
}

};



##### 11.3更新

CPU：Intel(R) Core(TM) i5-7200U CPU @ 2.50GHz 2.71GHz



CPU耗时（单位：s）

Debug版本0.7858.002
Release版本0.1641.724
• 5
点赞
• 19
收藏
觉得还不错? 一键收藏
• 11
评论
12-19
12-21
01-19
04-26
09-24
04-07
01-14 1073
05-30
12-22
04-04
09-24 590
06-17 326
02-16 2995

### “相关推荐”对你有帮助么？

• 非常没帮助
• 没帮助
• 一般
• 有帮助
• 非常有帮助

1.余额是钱包充值的虚拟货币，按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载，可以购买VIP、付费专栏及课程。