二柱子的难题02

老师又向二柱子提出一些要求,二柱子很崩溃

具体要求如下:

  1. 题目避免重复
  2. 可定制(数量/打印方式)

可控制参数
    1是否有乘除法
    2是否有括号
    3数值范围
    4加减法有无负数
    5除法有无余数

可怜的二柱子经过8h的奋战,终于在01版本的基础上改出了满足要求的02版本

  1 #include <iostream>
  2 #include <iomanip>
  3 #include <fstream>
  4 #include <ctime>
  5 #include <cstdlib>
  6 #include <sstream>
  7 #include <string>
  8 #include <vector>
  9 #include <algorithm>
 10 using namespace std;
 11
 12 bool isTrueFraction(int numerator, int denominator)    //判断产生的分数是否是真分数
 13 {
 14     if(numerator >= denominator)
 15         return false;
 16
 17     for(int i = 2 ; i <= numerator ; i++)      //判断分数是否能够约分
 18     {
 19         if(numerator % i ==0 && denominator % i ==0)
 20             return false;
 21     }
 22
 23     return true;
 24 }
 25
 26 string getNum(int start = 0, int end = 100, bool isParentheses = false, int depth = 0)
 27 {
 28     int n = rand();
 29     if(isParentheses)      // 若带括号 则为 a op ( b op c) 的形式 op为运算符
 30     {
 31         int num1 = rand() % (end - start + 1) + start;
 32         stringstream ss;
 33         ss << num1;
 34
 35         if(depth  < 9)     //控制递归层数,带括号的式子少于10个
 36         {
 37             string num2 = "(" + getNum(start,end, n % 2 == 0,depth + 1) + ")";
 38             return ss.str() +","+ num2;
 39         }
 40         else
 41         {
 42             string num2 = "(" + getNum(start,end, false) + ")";
 43             return ss.str() +","+ num2;
 44         }
 45     }else
 46     {
 47         if(n % 7 == 0)       //若随机数n是7的倍数,产生一个真分数和一个整数,否则为两个整数
 48         {
 49             int num1 = rand() % (end - start + 1) + start;
 50             int num2 = rand() % (end - start + 1) + start;
 51             int num3 = rand() % (end - start + 1) + start;
 52
 53             if(isTrueFraction(num1,num2))
 54             {
 55                 stringstream s1,s2,s3;   //将int转为string
 56                 s1<<num1;
 57                 s2<<num2;
 58                 s3<<num3;
 59                 return s1.str()+"/"+s2.str()+","+s3.str();
 60             }else
 61             {
 62                 return getNum(start,end);
 63             }
 64         }else
 65         {
 66             int num1 = rand() % (end - start + 1) + start;
 67             int num2 = rand() % (end - start + 1) + start;
 68             stringstream s1,s2;
 69             //string ss1,ss2;
 70             s1<<num1;
 71             s2<<num2;
 72             return s1.str()+","+s2.str();
 73         }
 74     }
 75
 76
 77 }
 78
 79 char getOperator(string num2 = "1", bool isMulandDiv = true)   // 默认第二个参数不为0,默认包括乘除法
 80 {
 81     char op[] = {‘+‘,‘-‘,‘*‘,‘/‘};
 82
 83     if(isMulandDiv)
 84     {
 85         if(num2 == "0") //避免除数为0
 86             return op[rand() % 3];
 87         else
 88             return op[rand() % 4];
 89     }else
 90     {
 91         return op[rand() % 2];     //只包含加减
 92     }
 93 }
 94
 95 bool isDup(vector<string> &items, string item)    //若重复返回true,否则返回false
 96 {
 97     if(find(items.begin(),items.end(),item) == items.end())
 98         return false;
 99     else
100         return true;
101 }
102
103 bool isNegative(string num1, string num2, char op)      //判断两数加减的正负
104 {
105     stringstream ss1,ss2;
106     int n1,n2;
107     ss1 << num1;
108     ss1 >> n1;
109     ss2 << num2;
110     ss2 >> n2;
111     if(op == ‘-‘)
112     {
113         if(n1 < n2)
114         {
115             return true;
116         }else
117         {
118             return false;
119         }
120     }else
121     {
122         if(n1 + n2 < 0)
123             return true;
124         else
125             return false;
126     }
127
128 }
129
130 bool isRemainder(string num1, string num2)   //判断两数相除有无余数
131 {
132     stringstream ss1,ss2;
133     int n1,n2;
134     ss1 << num1;
135     ss1 >> n1;
136     ss2 << num2;
137     ss2 >> n2;
138
139     if(n1 % n2 == 0)
140         return false;
141     else
142         return true;
143 }
144
145 void print(vector<string> &items, bool isCmd)
146 {
147     vector<string>::iterator it = items.begin();
148     if(isCmd)
149     {
150         for(;it != items.end(); it++)
151         {
152             cout << (*it) <<endl;
153         }
154     }else
155     {
156         ofstream of("problems.txt");
157         if(!of)
158             exit(1);
159
160         for(;it != items.end() ; it++)
161             of<<*it <<endl;
162
163         of.close();
164     }
165 }
166
167 //void itemsGenerate(int itemNum, bool isCmd)
168 //{
169
170 //}
171
172 int main(int argc, char *argv[])
173 {
174     srand((int)time(0));    //设定时间种子
175     vector<string> items;   //将题目存在items中,用于判断是否重复和输出
176     int itemNum,tmp;  //题目数量
177     char ttmp;
178     bool isCmd;    //打印方式
179     bool isMulandDiv;     //是否有乘除法
180     bool isParentheses;  //是否带括号
181     int start,end;  //数值范围
182     bool isNeg;    //有无负数
183     bool isRem;    //有无余数
184     bool addFlag = false;  //添加标识
185
186     cout << "请输入题目数量:" << endl;       //定制题目数量、打印方式等
187     cin >> itemNum;
188     if(itemNum < 0 )
189     {
190         cout << "非法的题目数量!" <<endl;
191         exit(1);
192     }
193
194     cout << "请输入打印方式(0. 输出到屏幕 1.输出到文件)" <<endl;
195     cin >> tmp;
196     if(tmp == 0)
197     {
198         isCmd = true;
199     }else if(tmp == 1)
200     {
201         isCmd = false;
202     }else
203     {
204         cout << "非法的打印方式!" <<endl;
205         exit(1);
206     }
207
208     cout << "请输入是否有乘除法(Y/N)" <<endl;
209     cin >>ttmp;
210     if(ttmp == ‘y‘ || ttmp == ‘Y‘)
211     {
212         isMulandDiv = true;
213     }else if (ttmp == ‘N‘ || ttmp == ‘n‘)
214     {
215         isMulandDiv = false;
216     }else
217     {
218         cout << "非法输入!"<<endl;
219         exit(1);
220     }
221
222     cout << "请输入是否有括号?(Y/N)" <<endl;
223     cin >>ttmp;
224     if(ttmp == ‘y‘ || ttmp == ‘Y‘)
225     {
226         isParentheses = true;
227     }else if (ttmp == ‘N‘ || ttmp == ‘n‘)
228     {
229         isParentheses = false;
230     }else
231     {
232         cout << "非法输入!"<<endl;
233         exit(1);
234     }
235
236     cout << "请输入数值范围:(中间由一空格分隔)" << endl;
237     cin >> start >> end ;
238     if(start > end)
239     {
240         swap(start, end);
241     }
242
243     cout << "加减法有无负数?(Y/N)" <<endl;
244     cin >> ttmp;
245     if(ttmp == ‘y‘ || ttmp == ‘Y‘)
246     {
247         isNeg = true;
248     }else if (ttmp == ‘N‘ || ttmp == ‘n‘)
249     {
250         isNeg = false;
251     }else
252     {
253         cout << "非法输入!"<<endl;
254         exit(1);
255     }
256
257     cout << "乘除法有无余数?(Y/N)" <<endl;
258     cin >> ttmp;
259     if(ttmp == ‘y‘ || ttmp == ‘Y‘)
260     {
261         isRem = true;
262     }else if (ttmp == ‘N‘ || ttmp == ‘n‘)
263     {
264         isRem = false;
265     }else
266     {
267         cout << "非法输入!"<<endl;
268         exit(1);
269     }
270
271
272     for(;items.size() != itemNum ;)    //根据条件生成问题
273     {
274         string num = getNum(start,end,isParentheses);
275         while (num.find(",") != string::npos)
276         {
277             addFlag = true;
278             if( num[num.find(",") + 1] == ‘(‘)     //运算符后紧跟括号,运算符选取只和isMulandDiv有关
279             {
280                 char op = getOperator("1",isMulandDiv);
281                 stringstream ss;
282                 ss << op;
283                 num = num.replace(num.find(","),1,ss.str());
284             }else                             //运算符后是数字,运算符选取和num2和isMulandDiv有关,此时是不带括号或最右边的算式
285             {
286                 //string::iterator it= num.find(",");
287                 string num2 = num.substr( num.find(",") + 1, num.find(")",num.find(",") + 1));
288                 char op = getOperator(num2,isMulandDiv);
289                 stringstream ss;
290                 ss << op;
291                 num = num.replace(num.find(","),1,ss.str());
292                 int begin = 0;    //找到形如 a op b 的式子
293                 if(num.find("(") != string::npos)
294                     begin = num.find_last_of("(") + 1;
295                 string num1 = num.substr(begin,num.find(ss.str()));
296                 num2 = num.substr(num.find_last_of(ss.str()) + 1,num.find_first_of(")"));
297                 if(op == ‘-‘ || op == ‘+‘)
298                 {
299
300                     if(!isNeg && isNegative(num1,num2,op))
301                     {
302                         addFlag = false;
303                         break;
304                     }
305
306                 }else if(op == ‘/‘)
307                 {
308                     if(!isRem && isRemainder(num1,num2))
309                     {
310                         addFlag = false;
311                         break;
312                     }
313                 }
314             }
315
316         }
317         if(!addFlag)    //满足要求,可以添加
318         {
319             continue;
320         }
321
322         if(!isDup(items,num))    //判断是否重复,不重复则添加
323         {
324             items.push_back(num);
325         }
326
327
328     }
329
330     print(items,isCmd);
331     return 0;
332 }

首先,用vector 存式子 ,1、方便检查重复 2、方便集中输出(屏幕或文件)

然后,生成式子带括号使用递归实现,通过depth控制深度,防止式子过长,getNum()获得参与运算的数,由“,”作为占位符,

等数值生成完毕后,在通过getOperator()获得运算符,此时运算符的获得由紧跟运算符后的数值和有无乘除的控制标识 共同决定,

P.S. 本程序考虑运算符,加减法有无负数,除法有无余数 仅考虑后面紧跟一个数值的情况,

如果后面是一个由“(”和“)”包围的式子,则不考虑了, 原谅我介一生不羁放纵爱自由 ~~~

从带括号的式子中取 子字符串 然后比较的部分在 271~314行,这部分比较绕,调试了很久。

附上一组测试数据: (把代码176~269行注释掉换成数据即可)

  /* 最常规的方式 */
    int itemNum = 10;  //题目数量
    bool isCmd = 0;    //打印方式 0.屏幕输出 1.文件输出
    bool isMulandDiv= true;     //是否有乘除法
    bool isParentheses = true;  //是否带括号
    int start = 0;    //数值范围起始
    int end = 100;  //数值范围结束
    bool isNeg = true;    //有无负数
    bool isRem = true;    //有无余数

    /*不带乘除法 数值范围为负 */
    int itemNum = 10;  //题目数量
    bool isCmd = 0;    //打印方式 0.屏幕输出 1.文件输出
    bool isMulandDiv = false;     //是否有乘除法
    bool isParentheses = true;  //是否带括号
    int start = -100;    //数值范围起始
    int end = 0;  //数值范围结束
    bool isNeg = true;    //有无负数
    bool isRem = true;    //有无余数

    /*文件输出 除法没余数 加减不为负*/
    int itemNum = 10;  //题目数量
    bool isCmd = 1;    //打印方式 0.屏幕输出 1.文件输出
    bool isMulandDiv = true;     //是否有乘除法
    bool isParentheses = true;  //是否带括号
    int start = 0;    //数值范围起始
    int end = 100;  //数值范围结束
    bool isNeg = false;    //有无负数
    bool isRem= false;    //有无余数

    /* 不带括号 */
    int itemNum = 10;  //题目数量
    bool isCmd = 0;    //打印方式 0.屏幕输出 1.文件输出
    bool isMulandDiv = true;     //是否有乘除法
    bool isParentheses = false;  //是否带括号
    int start = 0;    //数值范围起始
    int end = 100;  //数值范围结束
    bool isNeg = true;    //有无负数
    bool isRem = true;    //有无余数

    /*数值范围有正有负 */
    int itemNum = 10;  //题目数量
    bool isCmd = 0;    //打印方式 0.屏幕输出 1.文件输出
    bool isMulandDiv = true;     //是否有乘除法
    bool isParentheses = true;  //是否带括号
    int start = -100;    //数值范围起始
    int end = 100;  //数值范围结束
    bool isNeg = true;    //有无负数
    bool isRem = true;    //有无余数

    /*不生成式子 */
    int itemNum = 0;  //题目数量
    bool isCmd = 0;    //打印方式 0.屏幕输出 1.文件输出
    bool isMulandDiv = true;     //是否有乘除法
    bool isParentheses = true;  //是否带括号
    int start = 0;    //数值范围起始
    int end = 100;  //数值范围结束
    bool isNeg = true;    //有无负数
    bool isRem = true;    //有无余数

附上运行截图3张:

这是输出到文本里的

总之 ~~~

本部分任务算是完成了,如有问题 ,欢迎老师同学提出批评建议。

时间: 2024-11-10 01:05:05

二柱子的难题02的相关文章

二柱子四则运算3

二柱子四则运算3 可怜的二柱子……又一次被坑了…… 老师又在上次的“二柱子四则运算2”的基础上增添了要求,如下: 1.学生写的程序必须能判定用户的输入答案是否正确.直到题目结束,告诉用户做对了几道题. 2.程序必须能处理四种运算的混合模式. 注意:连续的减法和除法,应该遵守左结合的规定. 连续除法要打括号,否则会引起歧义. 一.实验思路 二.实验源代码 三.实验总结和反思 最后,附上我和我的小伙伴的工作照……没有正脸.老师们不要介意啦啦啦~~~~ 小伙伴博客内容页:http://www.cnbl

二柱子四则运算定制版+升级版

题目:在上次程序的基础上,实现对连除的判断,并且实现多个数的混合运算,要求可以输入结果,并进行判断. 思路:基于上次程序,首先思考混合运算,这里运用两个数组,分别记录随机产生的运算数和运算符号.然后对连除进行判断,,检查运算符号数组里是否有连续的除号,有的话加上括号,避免歧义.最后对运算结果进行计算,并对用户输入的结果进行比较,给出相应提示,回答,计算方面,要优先对括号,乘除进行运算,然后再进行加减运算,每次运算完后都要记录下运算的结果. 代码: //吕广浩 3/19 #include<iost

RIGHT-BICEP单元测试——“二柱子四则运算升级版”

RIGHT-BICEP单元测试 ——“二柱子四则运算升级版” ”单元测试“这对于我们来说是一个全新的专业含义,在上了软件工程这门课,并当堂编写了简单的"求一组数中的最大值"函数的单元测试之后,我们对它有了全新的认识. 单元测试:即为, 老师让我们回去之后将“二柱子四则运算升级版”的程序进行单元测试(二柱子程序的源码我已经上传,这里不再重复,只列举单元测试的部分和分析),如下: PS.这里附上老师上课讲的关于RIGHT-BICEP测试的方法: 6个值得测试的具体部位,他们能够提高我们的测

二柱子问题扩充:1、题目避免重复; 2、可定制(数量/打印方式); 3、可以控制下列参数: 是否有乘除法、是否有括号、 数值范围、加减有无负数、除法有无余数、否支持分数 (真分数, 假分数, …)、是否支持小数 (精确到多少位)、打印中每行的间隔可调整;

程序设计思想 程序的主要设计思想为用字符串数组保存生成的运算题,将操作数采用单独算法处理,然后进行类型转换和操作符一起存入数组中,鉴于字符串的特性,可以对字符串的长度进行随意添加而不必考虑长度问题,最后进行字符串数组的输出产生客户要求的运算题; 源代码 #include<stdlib.h> #include<conio.h> #include<time.h> #include<iostream> #include<string> #include

150313 那个可怜的二柱子同学

今天的软件工程概论课,老师出了这么个问题: 可怜的二柱子同学,老师又对他的自动出题系统提出了新的要求: 题目避免重复 可定制(数量.打印方式): 可以控制下列参数:是否有乘除法.数值范围.加减有无负数.除法有无余数.是否支持分数(真分数.假分数): 我想了两种解决方法: 一.使用数据库: 避免重复:随机数及符号大量生成录入数据库,生成md5,数据库查询(Select Distinct MD5,第一整数,符号,第二整数 from 题目表). 定制:输入框,输入题目数量.打印方式可以用[x++ if

二柱子的出题软件

二柱子的软件 支持真分数的四则运算 可定义出题数量 #define _CRT_SECURE_NO_DEPRECATE#include<stdio.h>#include<Windows.h>#include<time.h>int main(){ int a, b, c, d, e, f, g, k; float p, q; printf("请输入想要の数量"); scanf("%d",&k); srand(unsigned(

二柱子2.0编程总结

                                                                                时间记录表: 学生         王美仪                单位(分钟)         日期        2018.10.8             教师         王建民 日期 开始时间 结束时间 中断时间 净时间 活动 备注 2018.10.8 18:30 19:52 0 82 编程 基本完成 2018310.

二柱子升级版

一.实验思路二柱子的老师又提出了新的要求,要求能在线答题,保存错题.为了避免主函数代码过于重复,将"生成某一个范围内的随机数"."生成随机的分数"."生成一个运算符"."判断整数的正负并取相反数"."把int类型装换为string类型".以及"含有括号的运算"."含有真分数的运算"和"不含真分数的运算"等封装成函数.为了避免定义整型变量,计算时强制

苦逼的二柱子的四则运算问题

问题:二柱子将做好的项目交给了老师,几天后又得到新的需求:   1.实现在线答题:   2.答题结束后,可以判断对错:   3.并将错题的结果保存起来 #include<iostream>#include<stdarg.h>#include<stdlib.h>#include<time.h>#include<math.h>using namespace std;int main(){cout<<endl;cout<<&qu