解法1,对于任意输入的四个数字,给出一个24点的解法,若无解,则没有输出。
原理参照下图(编程之美原书)
代码如下,仅供参考
// 1.16.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <iostream> #include<string> #include "stdio.h" #include <math.h> using namespace std; const int CardsNumber = 4;//24点有四张卡 const double ErrorThreshold=1E-6;//由于舍入误差,需要加入一个误差阈值,误差在一定范围之内为,判断相等 const int ResultValue = 24; #define N 4 string result[CardsNumber]={"3","1","3","4"}; double number[CardsNumber]={3,1,3,4}; bool PointsGame(int n) { if(n == 1) { //如果结果为24 //由于舍入误差,应允许一定范围内的误差 if( fabs(number[0]-ResultValue)<ErrorThreshold) { cout<<result[0]<<endl; //cout<<'1'<<endl; return true; } else { return false; } } for(int i=0 ;i<n ;i++) { for(int j=i+1;j<n;j++) { double a,b; string expa,expb; a=number[i]; b=number[j]; number[j]=number[n-1]; expa=result[i]; expb=result[j]; result[j]=result[n-1]; result[i]='('+ expa +'+'+expb+')'; number[i]=a+b; if(PointsGame(n-1)) return true; result[i]='('+ expa +'-' + expb +')'; number[i]=a-b; if(PointsGame(n-1)) return true; result[i]='('+ expa + '*' + expb +')'; number[i]=a*b; if(PointsGame(n-1)) return true; if(b!=0) {result[i]='('+expa +'/'+ expb +')'; number[i]=a/b; if(PointsGame(n-1)) return true; } number[i]=a; number[j]=b; result[i]=expa; result[j]=expb; } } return false; } int _tmain(int argc, _TCHAR* argv[]) { PointsGame(4); return 0; }
解法2,可以返回,输入4个数字的情况下,一共有多少不同的解。
原理如下图(编程之美原书)
书中没有给出代码,分享下我的代码:
// 1.16.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <iostream> #include<string> #include "stdio.h" #include <math.h> using namespace std; const int CardsNumber = 4; const double ErrorThreshold=1E-6; const int ResultValue = 24; #define N 4 class doubleSet//以double数字为内容的集合 { public: doubleSet() { length=0; } doubleSet(double p[],int n) { length=n; for(int i=0;i<n;i++) { content[i]=p[i]; } } bool IsEmpty() { if(length==0 || length>65535) return true; else return false; } void Display()//显示该集合 { //content[length]='\0'; for(int i=0;i<length;i++) printf("%f ",content[i]); for(int i=0;i<length;i++) cout<<content[i]<<endl; } int GetLength() { return length; } double* Getcontent() { return content; } static doubleSet Union(doubleSet set1,doubleSet set2) //两个集合求交集 { int num1=set1.length; int num2=set2.length; if(num1==0) return set2; else if(num2==0) return set1; double *p1=set1.content; double *p2=set2.content; bool Repeat=0; for(int i=0;i<num2;i++) { for(int j=0;j<num1;j++) { if( *(p2+i)==*(p1+j)) { Repeat=1; break; } } if(Repeat==1) { Repeat=0; } else { num1++; *(p1+num1-1)=*(p2+i); } } set1.length=num1; for(int i=0;i<num1;i++) set1.content[i]=p1[i]; return set1; } private: int length;//length表示集合的长度 double content[500];//content代表集合中的内容 }; doubleSet fun(int i); doubleSet S[16]; //定义16个double数字集合 int Mycheck( doubleSet set)//check 最后有多少个结果为24 { int num=0; double *content=set.Getcontent(); for(int i=0;i<set.GetLength();i++) { if(fabs(content[i]-ResultValue)<ErrorThreshold) { num++; } } cout<<num<<endl; return num; } doubleSet Fork(doubleSet set1,doubleSet set2)//通过加减乘除合并两个数字集合为一个数字集合 { if(set2.IsEmpty()) return set1; if(set1.IsEmpty()) return set2; doubleSet ret; int retLen=0; double RetContent[500];//因为函数结束后,会释放局部变量,所以设置为静态的 //切记不要返回局部变量指着。 double *content1=set1.Getcontent(); double *content2=set2.Getcontent(); for(int i=0;i<set1.GetLength();i++) { for(int j=0;j<set2.GetLength();j++) { *(RetContent+retLen++)=content1[i]+content2[j]; *(RetContent+retLen++)=content1[i]-content2[j]; *(RetContent+retLen++)=content2[j]-content1[i]; *(RetContent+retLen++)=content1[i]*content2[j]; if(content2[j]!=0) *(RetContent+retLen++)=content1[i]/content2[j]; if(content1[i]!=0) *(RetContent+retLen++)=content2[j]/content1[i]; } } return doubleSet(RetContent,retLen); } void TheGame(doubleSet set) { //把i化为 2进制的数,第j位数为1的代表出现第j个数。 int n=set.GetLength(); //for(int i=1;i<=pow(2,n);i++) double *content1= set.Getcontent(); static double temp[4][1]; for(int i=0;i<n;i++)//先构造2的指数倍 { temp[i][0] = content1[i]; S[static_cast<int>(pow(2.0,i))]=doubleSet(temp[i],1); } for(int i=1;i<=pow(2.0,n)-1;i++) S[i]=fun(i);//fun返回该集合数字,通过四则运算可以返回的所有结果 Mycheck( S[static_cast<int> (pow(2.0,n)-1) ] ); } doubleSet fun(int i) { if(!S[i].IsEmpty()) return S[i]; for(int x=1;x<i;x++) { if((x&i)==x) S[i]=doubleSet::Union(S[i],Fork(fun(x),fun(i-x))); } return S[i]; } int _tmain(int argc, _TCHAR* argv[]) { double a[4]={3,6,3,4}; doubleSet set1=doubleSet(a,4); TheGame(set1); return 0; }
注:本文主要参考编程之美,1.16节给出的理论,主要目的是把代码贴出来给大家分享。
本文的图都来自《编程之美》
本人水平有限,怀着分享学习的态度发表此文,欢迎大家批评,交流。感谢您的阅读。
欢迎转载本文,转载时请附上本文地址:http://www.cnblogs.com/Dzhouqi/p/3362259.html
另外:欢迎访问我的博客 http://www.cnblogs.com/Dzhouqi/