目录
统计分析
从标有1-10的数字的10个小球中取出1个小球记录小球的数字,然后将小球放回,如此反复4次取出4小球的数字组成的序号一共有多少种。注意:1.1.8.9 和1.8.1.9 算是一种。
需要分为一下几种情况:
一个有10种
一共有10*9种 = 90
一共有10 * ( 9 * 8 /2 )种 = 360
10表示:10个相等的两个小球
( 9 * 8 /2 )表示:另外两个小球不相等的情况。
一共有(10*9)/2 中 = 45
= 10* 9 * 8 * 7 / (4 * 3 *2 *1 ) = 210
总数为=10 + 90 + 360 + 45 + 210 = 715
代码分析
代码中我们可以直接使用遍历的方式进行穷举,
1 . 对比记录列表中的数据是否存在,如果存在就忽略。
2. 如果不存在就添加到列表中。
遍历所有的数据。
- #define MAXNUM 10
- QList<struNum> initList()
- {
- QList<struNum> list;
- for (int i1 = 1;i1 <= MAXNUM; i1++) {
- for (int i2 = 1;i2 <= MAXNUM; i2++) {
- for (int i3 = 1;i3 <= MAXNUM; i3++) {
- for (int i4 = 1;i4 <= MAXNUM; i4++) {
- struNum num(i1,i2,i3,i4);
- if(!isInList(num,list)){
- list.append(num);
- }
- }
- }
- }
- }
- return list;
- }
判断是否存在列表中
- typedef struct SNUM{
- SNUM(int num1,int num2,int num3,int num4){
- this->num1 = num1;
- this->num2 = num2;
- this->num3 = num3;
- this->num4 = num4;
- }
- int num1 =0;
- int num2 =0;
- int num3 =0;
- int num4 =0;
- int c = 0; // 四个数能够计算24算法。
- }struNum;
- bool isInList(struNum num, QList<struNum> list)
- {
- int numList[4] = {num.num1,num.num2,num.num3,num.num4};
- bool result = false;
- for (int i1 = 0 ; i1 < 4; i1 ++) {
- for (int i2 = 0 ; i2 < 4; i2 ++){
- if(i1 == i2) continue;
- for (int i3 = 0 ; i3 < 4; i3 ++){
- if(i2 == i3 || i1 == i3) continue;
- for (int i4 = 0 ; i4 < 4; i4 ++){
- if(i1 == i4 || i2 == i4 || i3 == i4) continue;
- foreach(auto item ,list){
- if(item.num1 == numList[i1]
- && item.num2 == numList[i2]
- && item.num3 == numList[i3]
- && item.num4 == numList[i4]){
- result = true;
- }
- }
- }
- }
- }
- }
- return result;
- }
4个数按照顺序排列,一共有多少种排列方法。
我们可以使用遍历方法,将所有的数字进行遍历,那么可以得到一下算法。可以看到以下算法的步骤需要经过4*4*4*4 次运算。那么我们通过观察可以优化代码算法。
优化前
4*4*4*4 = 256次运算
-
- int numList[4] = {num1,num2,num3,num4};
-
- for (int i1 = 0 ; i1 < 4; i1 ++) {
- for (int i2 = 0 ; i2 < 4; i2 ++){
- for (int i3 = 0 ; i3 < 4; i3 ++){
- for (int i4 = 0 ; i4 < 4; i4 ++){
- if(i1 != i2 && i1 != i3 && i1 != i4 && i2 != i3 && i2 != i4 && i3 != i4){
- qInfo()<<numList[i1]<<" "<<numList[i2] <<" "<< numList[i3] <<" "<<" "<< numList[i4];
- c++;
- }
- }
- }
- }
- }
优化后
4*3*2 = 24 次运算。
- int numList[4] = {num1,num2,num3,num4};
- int c =0;
- for (int i1 = 0 ; i1 < 4; i1 ++) {
- for (int i2 = 0 ; i2 < 4; i2 ++){
- if(i1 == i2) continue;
- for (int i3 = 0 ; i3 < 4; i3 ++){
- if(i2 == i3 || i1 == i3) continue;
- for (int i4 = 0 ; i4 < 4; i4 ++){
- if(i1 == i4 || i2 == i4 || i3 == i4) continue;
- qInfo()<<numList[i1]<<" "<<numList[i2] <<" "<< numList[i3] <<" "<<" "<< numList[i4];
- c++;
- }
- }
- }
- }
由于计算过程中可能会遇到分数计算,因此我们不能使用int类型直接表示数据,或者是数据运算结果,我们定义一个分数类,专门用来计算分数的,加、减、乘、除,这样可以尽可能保存数据的正确性。
加法

减法

乘法

除法

LNum.h
- #ifndef LNUM_H
- #define LNUM_H
-
- class LNum
- {
-
- public:
- LNum(int Molecule);
- LNum(int Molecule,int Denominator);
- int getMolecule(); // 获取分子
- int getDenominator(); // 获取分母
- void setMolecule(int molecule); // 设置分子
- void setDenominator(int denominator);// 设置分母
- double data();
- LNum operator + ( LNum p1);
- LNum operator - ( LNum p1);
- LNum operator * ( LNum p1);
- LNum operator / ( LNum p1);
- bool operator ==( LNum p1) ;
- private:
- // 分子
- int m_iMolecule = 1;
- // 分母
- int m_iDenominator = 1;
- void Equivalency(); // 约分
-
- };
-
- #endif // LNUM_H
LNum.cpp
- #include "lnum.h"
-
-
- LNum::LNum(int num)
- :m_iMolecule(num)
- ,m_iDenominator(1)
- {
-
- }
-
- LNum::LNum(int Molecule, int Denominator)
- :m_iMolecule(Molecule)
- ,m_iDenominator(Denominator)
- {
-
- }
-
- int LNum::getMolecule()
- {
- Equivalency();
- return m_iMolecule;
- }
-
- int LNum::getDenominator()
- {
- Equivalency();
- return m_iDenominator;
- }
-
- void LNum::setMolecule(int molecule)
- {
- m_iMolecule = molecule;
- }
-
- void LNum::setDenominator(int denominator)
- {
- m_iDenominator = denominator;
- }
-
- double LNum::data()
- {
- Equivalency();
- if(m_iDenominator == 1){
- return m_iMolecule;
- }
- return double(m_iMolecule)/double(m_iDenominator);
- }
-
- void LNum::Equivalency()
- {
- int num = m_iMolecule> m_iDenominator?m_iDenominator:m_iMolecule;
-
- for (int i = 2 ; i < num ;i++) {
- if(m_iDenominator%i == 0 && m_iMolecule%i ==0){
- m_iDenominator = m_iDenominator/i;
- m_iMolecule = m_iMolecule/i;
- num = m_iMolecule> m_iDenominator?m_iDenominator:m_iMolecule;
- }
- }
- }
-
- LNum LNum::operator +(LNum p1)
- {
- LNum res(getMolecule(),getDenominator());
- res.setMolecule(getMolecule()*p1.getDenominator() + getDenominator()*p1.getMolecule());
- res.setDenominator(getDenominator()*p1.getDenominator());
- return res;
- }
-
- LNum LNum::operator -(LNum p1)
- {
- LNum res(getMolecule(),getDenominator());
- res.setMolecule(getMolecule()*p1.getDenominator() - getDenominator()*p1.getMolecule());
- res.setDenominator(getDenominator()*p1.getDenominator());
- return res;
- }
-
- LNum LNum::operator *(LNum p1)
- {
- LNum res(getMolecule(),getDenominator());
- res.setMolecule(getMolecule()*p1.getMolecule());
- res.setDenominator(getDenominator()*p1.getDenominator());
- return res;
- }
-
- LNum LNum::operator /(LNum p1)
- {
- LNum res(getMolecule(),getDenominator());
- res.setMolecule(getMolecule()*p1.getDenominator());
- res.setDenominator(getDenominator()*p1.getMolecule());
- return res;
- }
-
- bool LNum::operator ==(LNum p1)
- {
- if (getMolecule() == p1.getMolecule() && getDenominator() == p1.getDenominator()) {
- return true;
- }
- else{
- return false;
- }
-
- }
第一步将操作符数字化,方便遍历。可以得到如下公式。x为操作符标识。
- double jisuan(LNum num1,LNum num2,int x){
- switch (x) {
- case 0:
- return num1+num2;
- case 1:
- return num1-num2 ;
- case 2:
- return num1*num2;
- case 3:
- return num1/num2 ;
- }
- return 0;
- }
循环遍历4个数的不同位置,并且循环遍历算法。判断其内容是否为24如果是24那么表示可以计算成功。
- int is24OK(LNum num1, LNum num2, LNum num3, LNum num4)
- {
- int result = 0;
- QList<struRecordNum> list;
- LNum numList[4] = {num1,num2,num3,num4};
- // 交换4个数字的顺序。
- for (int i1 = 0 ; i1 < 4; i1 ++) {
- for (int i2 = 0 ; i2 < 4; i2 ++){
- if(i1 == i2) continue;
- for (int i3 = 0 ; i3 < 4; i3 ++){
- if(i2 == i3 || i1 == i3) continue;
- for (int i4 = 0 ; i4 < 4; i4 ++){
- if(i1 == i4 || i2 == i4 || i3 == i4) continue;
- // qInfo()<<numList[i1]<<" "<<numList[i2] <<" "<< numList[i3] <<" "<<" "<< numList[i4];
- int x=suanfatongji(numList[i1],numList[i2],numList[i3],numList[i4],&list);
- if(x !=0){
- qInfo()<<"x:"<<x;
- result += x;
- }
- }
- }
- }
- }
- return result;
- }
-
- int suanfatongji(LNum num1, LNum num2, LNum num3, LNum num4, QList<struRecordNum> *list)
- {
- LNum sum = 0;
-
- int c= 0;
- for(int i1 = 0 ; i1 < 4; i1 ++){
- for(int i2 = 0 ; i2 < 4; i2 ++ ){
- for(int i3 = 0 ; i3 < 4; i3 ++){
- sum = jisuan(jisuan(jisuan (num1,num2,i1),num3,i2),num4,i3) ;
- if(24.0 == sum.data()){
- // 是否找到相同的算法,因为有重复数字可能导致算法想法和数字相同的情况。
- bool result = false;
- for(auto item : *list){
- if(item.num1 == static_cast<int>(num1.data())
- && item.num2 == static_cast<int>(num2.data())
- && item.num3 == static_cast<int>(num3.data())
- && item.num4 == static_cast<int>(num4.data())
- && item.option1 == i1
- && item.option2 == i2
- && item.option3 == i3){
- result = true;
- }
- }
- if(!result){
- struRecordNum tmpItem;
- tmpItem.num1 = static_cast<int>(num1.data());
- tmpItem.num2 = static_cast<int>(num2.data());
- tmpItem.num3 = static_cast<int>(num3.data());
- tmpItem.num4 = static_cast<int>(num4.data());
- tmpItem.option1 = i1;
- tmpItem.option2 = i2;
- tmpItem.option3 = i3;
- list->append(tmpItem);
- c++;
- qInfo()<< "(( "<< num1.data() <<strOption(i1) << num2.data() <<")"<<strOption(i2)<< num3.data()<<")" <<strOption(i3)<< num4.data();
- }
- }
- }
- }
- }
- return c;
- }
啊渊 / QT博客案例 · GitCode 24点题库分析。