// Num.h
#include <iostream>
#include <vector>
#include <string>
using namespace std;
typedef float (*PF)(float, float);
class Num
{
public:
Num();
~Num();
bool Compute() const;
static float Func1(float a, float b);
static float Func2(float a, float b);
static float Func3(float a, float b);
static float Func4(float a, float b);
private:
vector< float > *m_vf;
static const PF m_pf[4];
static const string op;
};
// Num.cpp
#include "Num.h"
float Num::Func1(float a, float b)
{
return a+b;
}
float Num::Func2(float a, float b)
{
return a-b;
}
float Num::Func3(float a, float b)
{
return a*b;
}
float Num::Func4(float a, float b)
{
return a/b;
}
const string Num::op = "+-*/";
const PF Num::m_pf[4] = {Num::Func1, Num::Func2, Num::Func3, Num::Func4};
Num::Num()
{
cout<<"Please input the num:"<<endl;
m_vf = new vector<float>;
if (m_vf == NULL)
{
cerr<<"There is no enough momery!"<<endl;
exit(1);
}
for (int i = 0; i < 4; i++)
{
float temp;
cin>>temp;
m_vf->push_back(temp);
}
}
Num::~Num()
{
delete m_vf;
}
bool Num::Compute() const
{
bool res = false;
//四个for列出四个数字的全排列
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)
for (int k = 0; k < 4; k++)
for (int h=0; h < 4; h++)
{
if (i!=j && i!=k && i!=h && j!=k && j!=h && k!=h)
{
//三个for列出一个数字排列加入运算符后的计算组合
for (int l = 0; l < 4; l++)
for (int m = 0; m < 4; m++)
for (int n = 0; n < 4; n++)
{
//考虑运算符优先级以及括号
//a(b(cd))
float temp = m_pf[l]( (*m_vf)[i], m_pf[m]( (*m_vf)[j], m_pf[n]( (*m_vf)[k], (*m_vf)[h]) ) );
if (23.9 < temp && temp < 24.1)
{
cout<<(*m_vf)[i]<<op[l]<<'('
<<(*m_vf)[j]<<op[m]<<'('
<<(*m_vf)[k]<<op[n]
<<(*m_vf)[h]<<")) = 24"<<endl;
res = true;
}
//(ab)(cd)
temp = m_pf[m]( m_pf[l]( (*m_vf)[i], (*m_vf)[j] ), m_pf[n]( (*m_vf)[k], (*m_vf)[h] ) );
if (23.9 < temp && temp < 24.1)
{
cout<<'('<<(*m_vf)[i]<<op[l]
<<(*m_vf)[j]<<')'<<op[m]<<'('
<<(*m_vf)[k]<<op[n]
<<(*m_vf)[h]<<") = 24"<<endl;
res = true;
}
//a((bc)d)
temp = m_pf[l]( (*m_vf)[i], m_pf[n]( m_pf[m]( (*m_vf)[j], (*m_vf)[k] ), (*m_vf)[h] ) );
if (23.9 < temp && temp < 24.1)
{
cout<<(*m_vf)[i]<<op[l]<<"(("
<<(*m_vf)[j]<<op[m]
<<(*m_vf)[k]<<')'<<op[n]
<<(*m_vf)[h]<<") = 24"<<endl;
res = true;
}
//(a(bc))d
temp = m_pf[n]( m_pf[l]( (*m_vf)[i] , m_pf[m]( (*m_vf)[j], (*m_vf)[k] ) ), (*m_vf)[h] );
if (23.9 < temp && temp < 24.1)
{
cout<<'('<<(*m_vf)[i]<<op[l]<<'('
<<(*m_vf)[j]<<op[m]
<<(*m_vf)[k]<<"))"<<op[n]
<<(*m_vf)[h]<<" = 24"<<endl;
res = true;
}
//((ab)c)d
temp = m_pf[n]( m_pf[m]( m_pf[l]( (*m_vf)[i], (*m_vf)[j] ), (*m_vf)[k] ), (*m_vf)[h] );
if (23.9 < temp && temp < 24.1)
{
cout<<"(("<<(*m_vf)[i]<<op[l]
<<(*m_vf)[j]<<')'<<op[m]
<<(*m_vf)[k]<<')'<<op[n]
<<(*m_vf)[h]<<" = 24"<<endl;
res = true;
}
}
}
}
return res;
}
//main.cpp
#include "Num.h"
int main()
{
Num eg;
if ( !eg.Compute() )
{
cout<<"The 4 numbers can not return 24!"<<endl;
}
return 0;
}
几点说明:
1、Func1~Func4可以合并成一个函数Func(float a, float b, int c)用c来判断是进行哪种运算,这样就不用定义一个函数指针数组,这样就可以把Func放到private区有利于更好的封装,不过可能要影响程序的可读性;
2、对于四个输入数字的全排列,可以考虑使用范型算法next_permutation(),它将[first,last)之间的元素重新排序为下一个排列,如果不存在下一个排列则返回false;由于算法的排序特征(从升序排到降序为止),所以进入循环前必须先对元素进行排序,且至少要保证一次循环,所以采用do-while循环。采用范型算法实现还有一个优点就是对于有相等数字的排列(1667),其只计算了一组。而上面的算法则计算了两组(两个6交换了位置)。
3、语法层次上要注意类静态成员的声明与定义方法(ODR法则);
4、注意vector的用法,思考下为什么类成员变量要定义为vector的指针,如果我们用数组来实现,那么这个类的构造函数又应该如何改写呢?
#include <iostream>
#include <vector>
#include <string>
using namespace std;
typedef float (*PF)(float, float);
class Num
{
public:
Num();
~Num();
bool Compute() const;
static float Func1(float a, float b);
static float Func2(float a, float b);
static float Func3(float a, float b);
static float Func4(float a, float b);
private:
vector< float > *m_vf;
static const PF m_pf[4];
static const string op;
};
// Num.cpp
#include "Num.h"
float Num::Func1(float a, float b)
{
return a+b;
}
float Num::Func2(float a, float b)
{
return a-b;
}
float Num::Func3(float a, float b)
{
return a*b;
}
float Num::Func4(float a, float b)
{
return a/b;
}
const string Num::op = "+-*/";
const PF Num::m_pf[4] = {Num::Func1, Num::Func2, Num::Func3, Num::Func4};
Num::Num()
{
cout<<"Please input the num:"<<endl;
m_vf = new vector<float>;
if (m_vf == NULL)
{
cerr<<"There is no enough momery!"<<endl;
exit(1);
}
for (int i = 0; i < 4; i++)
{
float temp;
cin>>temp;
m_vf->push_back(temp);
}
}
Num::~Num()
{
delete m_vf;
}
bool Num::Compute() const
{
bool res = false;
//四个for列出四个数字的全排列
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)
for (int k = 0; k < 4; k++)
for (int h=0; h < 4; h++)
{
if (i!=j && i!=k && i!=h && j!=k && j!=h && k!=h)
{
//三个for列出一个数字排列加入运算符后的计算组合
for (int l = 0; l < 4; l++)
for (int m = 0; m < 4; m++)
for (int n = 0; n < 4; n++)
{
//考虑运算符优先级以及括号
//a(b(cd))
float temp = m_pf[l]( (*m_vf)[i], m_pf[m]( (*m_vf)[j], m_pf[n]( (*m_vf)[k], (*m_vf)[h]) ) );
if (23.9 < temp && temp < 24.1)
{
cout<<(*m_vf)[i]<<op[l]<<'('
<<(*m_vf)[j]<<op[m]<<'('
<<(*m_vf)[k]<<op[n]
<<(*m_vf)[h]<<")) = 24"<<endl;
res = true;
}
//(ab)(cd)
temp = m_pf[m]( m_pf[l]( (*m_vf)[i], (*m_vf)[j] ), m_pf[n]( (*m_vf)[k], (*m_vf)[h] ) );
if (23.9 < temp && temp < 24.1)
{
cout<<'('<<(*m_vf)[i]<<op[l]
<<(*m_vf)[j]<<')'<<op[m]<<'('
<<(*m_vf)[k]<<op[n]
<<(*m_vf)[h]<<") = 24"<<endl;
res = true;
}
//a((bc)d)
temp = m_pf[l]( (*m_vf)[i], m_pf[n]( m_pf[m]( (*m_vf)[j], (*m_vf)[k] ), (*m_vf)[h] ) );
if (23.9 < temp && temp < 24.1)
{
cout<<(*m_vf)[i]<<op[l]<<"(("
<<(*m_vf)[j]<<op[m]
<<(*m_vf)[k]<<')'<<op[n]
<<(*m_vf)[h]<<") = 24"<<endl;
res = true;
}
//(a(bc))d
temp = m_pf[n]( m_pf[l]( (*m_vf)[i] , m_pf[m]( (*m_vf)[j], (*m_vf)[k] ) ), (*m_vf)[h] );
if (23.9 < temp && temp < 24.1)
{
cout<<'('<<(*m_vf)[i]<<op[l]<<'('
<<(*m_vf)[j]<<op[m]
<<(*m_vf)[k]<<"))"<<op[n]
<<(*m_vf)[h]<<" = 24"<<endl;
res = true;
}
//((ab)c)d
temp = m_pf[n]( m_pf[m]( m_pf[l]( (*m_vf)[i], (*m_vf)[j] ), (*m_vf)[k] ), (*m_vf)[h] );
if (23.9 < temp && temp < 24.1)
{
cout<<"(("<<(*m_vf)[i]<<op[l]
<<(*m_vf)[j]<<')'<<op[m]
<<(*m_vf)[k]<<')'<<op[n]
<<(*m_vf)[h]<<" = 24"<<endl;
res = true;
}
}
}
}
return res;
}
//main.cpp
#include "Num.h"
int main()
{
Num eg;
if ( !eg.Compute() )
{
cout<<"The 4 numbers can not return 24!"<<endl;
}
return 0;
}
几点说明:
1、Func1~Func4可以合并成一个函数Func(float a, float b, int c)用c来判断是进行哪种运算,这样就不用定义一个函数指针数组,这样就可以把Func放到private区有利于更好的封装,不过可能要影响程序的可读性;
2、对于四个输入数字的全排列,可以考虑使用范型算法next_permutation(),它将[first,last)之间的元素重新排序为下一个排列,如果不存在下一个排列则返回false;由于算法的排序特征(从升序排到降序为止),所以进入循环前必须先对元素进行排序,且至少要保证一次循环,所以采用do-while循环。采用范型算法实现还有一个优点就是对于有相等数字的排列(1667),其只计算了一组。而上面的算法则计算了两组(两个6交换了位置)。
3、语法层次上要注意类静态成员的声明与定义方法(ODR法则);
4、注意vector的用法,思考下为什么类成员变量要定义为vector的指针,如果我们用数组来实现,那么这个类的构造函数又应该如何改写呢?