C++实现24点

   24 点这个是比较经典的习题,里面涉及到排列组合以及如何处理四则混合运算的优先级问题。上一次解的时候使用后续表达式,不用取括号。没有考虑两两组合的计算。导致有些组合不能运算,3 3 3 1 (3+3)*(3+1) 能够得到24,确由于只是顺序计算导致算法不对。

   这次使用的思想如下:

1 选择两个数字,生成数字 P(4 2) = 6
2 选择符号,生成S 表达式 P(4 1)    = 4
重复上面步骤直到为一个数字

/**
 *    \fn void calc(VALUE_DESC value,VEC_DESC &vec,VEC_DESC &result)
 *    \brief 递归计算vec和输入的value 之间的值,结果保存result
 *    \param value - 输入的值,初始值为0
 *    \param vec - 一组数,初始为4个数
 *    \param result - 结果为最终通过四则混合运算计算的可能结果,很多很多
 */
void calc(VALUE_DESC value,VEC_DESC &vec,VEC_DESC &result)

初始值 value = 0 vec 为输入的元素 比如为 [ 3 3 3 1],result 保存结果,当计算完成的时候

value ==0 顶层运算 ,将vec分为 【vec[i]】   【剩下的元素】两个集合,并且递归调用 calc

                                      如果vec 个数为1 个那么证明计算完毕,将结果写入result

value !=0 那么计算 value 和 vec 中各个元素的可能的结果,将结果和vec-i 合并,得 vec.size() 个元素的组并且状态转向 value==0

状态机:

  0 状态 <-------------> 1 状态

状态转化条件是 为0则到1 为1 则到0 ,直到计算完毕


代码如下:

// to24point1.cpp : 定义控制台应用程序的入口点。
//
#include <tchar.h>
#include <vector>
#include <string>
using namespace std;
//因为中间结果可能有非整数,所以使用float 保存数值
typedef pair<float,string> VALUE_DESC;
//
typedef vector<VALUE_DESC> VEC_DESC;
/**
 *	\fn string gen_op(char* op,string &desc1,string &desc2)
 *	\brief 生成二值计算的表达式
 *	\param op 操作符 + - * /
 *	\param desc1 第一个操作数的表达式
 *	\param desc2 第二个操作数的表达式
 */
string gen_op(char* op,string &desc1,string &desc2)
{
	string result ="(";
	result.append(op);
	result.push_back(' ');
	result.append(desc1);
	result.push_back(' ');
	result.append(desc2);
	result.push_back(')');
	return result;
}

/**
 *	\fn VEC_DESC four_calc(VALUE_DESC &a1,VALUE_DESC &a2)
 *	\brief 四则运算
 *	\param a1 --第一个值和它的表达式
 *	\param a2 --第二个值和它的表达式
 *	\return 值和它的表达式
 */
VEC_DESC four_calc(VALUE_DESC &a1,VALUE_DESC &a2)
{
#define APPEND_RESULT(vec,op,a1,a2) vec.push_back(make_pair(a1.first##op##a2.first,gen_op(#op,a1.second,a2.second)));
	VEC_DESC result ;
	char op[4] ={'+','-','*','/'};
	for(int i=0;i<4;i++)
	{
		char c = op[i];
		switch(c)
		{
		case '+':
			{
				APPEND_RESULT(result,+,a1,a2);
				break;
			}
		case '-':
			{			
				APPEND_RESULT(result,-,a1,a2);
				APPEND_RESULT(result,-,a2,a1);
				break;
			}
		case '*':
			{	
				APPEND_RESULT(result,*,a1,a2);				
				break;
			}	
		case '/':
			{			
				if(a1.first!=0)
				{
					APPEND_RESULT(result,/,a2,a1);
				}
				if(a2.first!=0)
				{
					APPEND_RESULT(result,/,a1,a2);
				}
				break;
			}

		}
 	}
	return result;
}
/**
 *	\fn void calc(VALUE_DESC value,VEC_DESC &vec,VEC_DESC &result)
 *	\brief 递归计算vec和输入的value 之间的值,结果保存result
 *	\param value - 输入的值,初始值为0
 *	\param vec - 一组数,初始为4个数
 *	\param result - 结果为最终通过四则混合运算计算的可能结果,很多很多
 */
void calc(VALUE_DESC value,VEC_DESC &vec,VEC_DESC &result)
{
	if(value.first==0)//还没有中间结果
	{
		if(vec.size()==1) //得到结果
		{
			result.push_back(vec[0]);
			return ;
		}
		for(size_t i=0;i<vec.size();i++) //顶层的计算,4个则可能有4种取的可能
		{
			VEC_DESC t = vec;
			t.erase(t.begin()+i);
			calc(vec[i],t,result);//输出可能的值
		}
	}
	else
	{
		//有了中间结果,从vec中获取1个元素,参与运算,结果继续运算
		for(size_t i=0;i<vec.size();i++) 
		{
			VEC_DESC t = vec;
			t.erase(t.begin()+i);
			//中间结果
			VEC_DESC vcalc=four_calc(value,vec[i]);
			for(size_t j=0;j<vcalc.size();j++)
			{
				VEC_DESC tt = t;
				tt.push_back(vcalc[j]);
				//中间结果,剩下的元素,结果
				calc(make_pair(0.0,string("")),tt,result);
			}
		}
	}
}
//初始化数据
void init_vec_desc(VEC_DESC &vec,int value[],int len)
{
	for(int i=0;i<len;i++)
	{
		char buf[10]={};
		itoa(value[i],buf,10);

		vec.push_back(make_pair(value[i],buf));
	}
}
//获得等于24的结果
VALUE_DESC get_correct_value(VEC_DESC &r)
{
	for(size_t i=0;i<r.size();i++)
	{
		if(r[i].first >=24.0000000 && r[i].first<24.00000001 )
		{
			return r[i];
		}
	}
	return make_pair(0,"");
}
int to24(VEC_DESC &vec)
{
	VEC_DESC r;
	calc(make_pair(0.0,string("")),vec,r);
	VALUE_DESC result = get_correct_value(r);
	if(result.first==0)
	{
		printf("[%d %d %d %d] cannot calculate 24\n",(int)vec[0].first,(int)vec[1].first,(int)vec[2].first,(int)vec[3].first);
	}
	else
	{
	printf("[%d %d %d %d] : %s\n",(int)vec[0].first,(int)vec[1].first,(int)vec[2].first,(int)vec[3].first,result.second.c_str());
	}
	return 0 ;
}
void test()
{
	VEC_DESC input;
	VEC_DESC r;	
	int buf[][4]={
			{5,1,4,2},
			{3,3,3,1},
			{5,5,5,1},
			{1,1,6,8},
			{1,1,6,9},
			{1,1,7,10},
			{1,1,8,8},
	};
	for(int i=0;i<sizeof(buf)/sizeof(buf[0]);i++)
	{
		input.clear();
		init_vec_desc(input,buf[i],4);
		to24(input);
	}
}
void test1()
{
	int i,j,k,m;
	for(i=1;i<=13;i++)
		{
		for(j=1;j<=13;j++)
			{
			for(k=1;k<=13;k++)
				{
				for(m=1;m<=13;m++)
					{
					VEC_DESC input;
					int buf[4]={i,j,k,m};
					init_vec_desc(input,buf,4);
					to24(input);
					}
				}
			}
		}
}
int _tmain(int argc, _TCHAR* argv[])
{
	test1();
	return 0;
	VEC_DESC input;
	VEC_DESC r;
	int buf[4]={5,1,4,2};
	printf("\nPlease input 4 number:");
	scanf("%d%d%d%d",&buf[0],&buf[1],&buf[2],&buf[3]);
	init_vec_desc(input,buf,4);
	to24(input);

	return 0;
}



  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值