解法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/
