二柱子的难题02
Posted _Just
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二柱子的难题02相关的知识,希望对你有一定的参考价值。
老师又向二柱子提出一些要求,二柱子很崩溃
具体要求如下:
- 题目避免重复
- 可定制(数量/打印方式)
可控制参数
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张:
这是输出到文本里的
总之 ~~~
本部分任务算是完成了,如有问题 ,欢迎老师同学提出批评建议。
以上是关于二柱子的难题02的主要内容,如果未能解决你的问题,请参考以下文章