关于24点游戏的编程思路与基本算法

关于24点游戏的编程思路与基本算法
 

24点游戏的算法,其中最主要的思想就是穷举法。所谓穷举法就是列出4个数字加减乘除的各种可能性,包括括号的算法。我们可以将表达式分成以下几种:首先我们将4个数设为abcd,,其中算术符号有+-*/,。其中有效的表达式有aab-cd,等等。列出所有有效的表达式。其中我们用枚举类型将符号定义成数字常量,比如用1表示+2表示-等。如下是我对穷举法的一种编程语言。在编程的头部要对变量做下定义。其中abcd的范围是110。这就需要在定义变量的时候要有限制。在vc++中的编程中,在定义控件的变量范围可以直接填写变量的最大和最小,在此编程中的最大是10,最小是1。这就给编程写语句带来了方便。 

运用C/C++语言开发工具Microsoft Visual C++ 6.0,利用它简单、明了的开发特点对课本知识进行系统的实践,并且通过对各个知识点的运用进行所需的程序编写。首先,要充分理解每个程序涉及的算法,牢记实现算法的每一个步骤;其次,再在计算机上利用C语言编写出代码,要求结构清晰,一目了然;最后,要对程序进行优化,使程序实现优秀的运行功能。在编写程序的过程中要充分理解并能熟练使用对应的算法,竟可能多的涉及课本中的知识点。总之通过实行整体方案,最终使程序达到运行状态,并且实现良好的运行效果。

故做了如下的计划安排,将这项工程分为两大部分:程序的设计和程序的调试。

首先在程序的设计部分由分为几个步骤:

第一步:查阅有关归并排序算法的资料。

第二步:设计这个项目的整体架构和算法。

第三步:选择一门程序设计语言进行算法的描述。

其次,进行程序的调试。

设计方法和内容

在做某件事时,一个好的方法往往能起到事半功倍的效果。在这个课程的设计上,我选择了C++语言作为算法的描述语言,因为C++语言具有丰富的表达能力以及代码的高效性,并且有着良好的移植性和灵活性。同时,采用“自顶向下,个个击破”的程序设计思路和思想,充分运用C++语言强大的功能。使该课程设计做起来更加的简单。

我将这个课程设计整体分成了两个部分。一个是数据结构定义部分和算法部分。这两大部分有机的结合共同构成了该课程设计的程序,运行该程序就可以将该课程设计的功能实现了。

程序的设计思想和内容

(一)算法一:

24点游戏的算法,其中最主要的思想就是穷举法。所谓穷举法就是列出4个数字加减乘除的各种可能性。我们可以将表达式分成以下几种:首先我们将4个数设为a,b,c,d,,将其排序列出四个数的所有排序序列组合(共有A44=24种组合)。再进行符号的排列表达式,其中算术符号有+,—,*/,(,)。其中有效的表达式有a*(b-c/b)a*b-c*d,等等。列出所有有效的表达式。其中我们用枚举类型将符号定义成数字常量。如下是我对穷举法的一种编程语言。在编程的头部要对变量做下定义。其中a,b,c,d的范围是110。这就需要在定义变量的时候要有限制。在vc++中的MFC编程中,在定义控件的变量范围可以直接填写变量的最大和最小,在此编程中的最大是10,最小是1。这就给编程写语句带来了方便(因为其自动会生成语句)。下面我介绍下穷举法的主要实现,我们知道要实现24点的算法,就是通过4个数字,4个运算符号和2对括号(最多为2对),通过各种组合判断其结果是否为24。我们用abc,d代替4个数字。考虑每种可能,总的算法就有7种可能。分别为:

1没括号的(形如a*b*c*d);

2有括号的(形如(a * b) * c * d);

3有括号的(形如(a * b * c) * d);

4有括号的(形如a * (b * c) * d);

5有括号的(形如(a * b) * (c * d));

6有括号的(形如((a * b) * c) * d);

7有括号的(形如(a * (b * c)) * d)。

接下来就是对每一种进行分析判断。

以上就是穷举法的基本实现算法

 首先穷举的可行性问题。我把表达式如下分成三类:

1 列出四个数的所有排序序列组合(共有A44=24种组合)。

 2 构筑一个函数,列出所有运算表达式。

 3 输入数据计算。

(二)算法二:

24点游戏的算法,还有另外一种算法。

     把多元运算转化为两元运算,先从四个数中取出两个数进行运算,然后把运算结果和第三个数进行运算,再把结果与第四个数进行运算。在求表达式的过程中,最难处理的就是对括号的处理,而这种思路很好的避免了对括号的处理。基于这种思路的一种算法:

因为能使用的4种运算符 * / 都是2元运算符,所以本文中只考虑2元运算符。2元运算符接收两个参数,输出计算结果,输出的结果参与后续的计算。

 

  由上所述,构造所有可能的表达式的算法如下:

  (1) 4个整数放入数组中

  (2) 在数组中取两个数字的排列,共有 P(4,2) 种排列。对每一个排列,

  (2.1) * / 每一个运算符,

  ( 2.1.1 ) 根据此排列的两个数字和运算符,计算结果

  ( 2.1.2 ) 改表数组:将此排列的两个数字从数组中去除掉,将 2.1.1 计算的结果放入数组中

  ( 2.1.3 ) 对新的数组,重复步骤 2

  ( 2.1.4 ) 恢复数组:将此排列的两个数字加入数组中,将 2.1.1 计算的结果从数组中去除掉

  可见这是一个递归过程。步骤 2 就是递归函数。当数组中只剩下一个数字的时候,这就是表达式的最终结果,此时递归结束。

  在程序中,一定要注意递归的现场保护和恢复,也就是递归调用之前与之后,现场状态应该保持一致。在上述算法中,递归现场就是指数组, 2.1.2 改变数组以进行下一层递归调用,2.1.3 则恢复数组,以确保当前递归调用获得下一个正确的排列。

  括号 () 的作用只是改变运算符的优先级,也就是运算符的计算顺序。所以在以上算法中,无需考虑括号。括号只是在输出时需加以考虑。

void Chazhao(int n) { 

      if (n == 1) { 

          if ( fabs(number[0] - VOLUE) <= LING   ) //对于除法,要小心小数的精确位数

   {                cout << biaodashi[0] << "\t\t";

      Panduan = true;

      count ++;

      if((count % 3)==0) //使输出时每行三个表达式

       cout<<endl;

           

   else

   {  

      

       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];   //递归之后,n比以前小一位,所以可以不停向前赋值

   expa = biaodashi[i]; 

        expb = biaodashi[j]; 

        biaodashi[j] = biaodashi[n - 1]; //递归之后,n比以前小一位,所以可以不停向前赋值

         biaodashi[i]= '('+ expa + '+' + expb + ')';   //加法不需要分顺序

         number[i] = a + b; 

         Chazhao(n-1);

         biaodashi[i]='('+ expa+ '-' + expb + ')';   //减法应该分顺序,减数以及被减数

         number[i] = a - b; 

         Chazhao(n-1);  

         biaodashi[i] = '('+expb + '-' + expa + ')';   //减法应该分顺序,减数以及被减数

         number[i] = b -a; 

         Chazhao(n-1);                                            

         biaodashi[i]= '('+ expa +'*'+ expb+ ')';   //乘法不需要分顺序

         number[i]=a*b; 

         Chazhao(n-1); 

        if (b != 0) {

         biaodashi[i] ='('+expa+'/' + expb + ')';   //除法应该分顺序,除数以及被除数

         number[i] = a / b; 

         Chazhao(n-1); 

       }   

        if (a != 0) { 

            biaodashi[i]='('+expb + '/'+ expa + ')';   //除法应该分顺序,除数以及被除数

            number[i] = b / a; 

            Chazhao(n-1); 

     

       number[i] =a;         //4句语句是为了防止如果上面几种可能都失败了的话,

       number[j]=b;         //就把原来的赋值撤消回去,以无干扰的正确的进入到下一次

       biaodashi[i] = expa;           //for循环队列中。

       biaodashi[j] = expb;           //

               

    }

附录原程序代码

算法一:

#include <iostream>

using namespace std;

int main()

{ float a,b,c,d;

fanhui:                //做标记

cout<<"请输入4个数据"<<endl;

cout<<" 第一个数:";

cin>>a;

cout<<" 第二个数:";

cin>>b;

cout<<" 第三个数:";

cin>>c;

cout<<" 第四个数:";

cin>>d;

cout<<"输出所有算法如下:"<<endl;

if ((a<0)||(a>10)||(b<0)||(b>10)||(c<0)||(c>10)||(d<0)||(d>10))

{ cout<<"你输入的输入不对,重新输入"<<endl;

 

goto fanhui; }       // 返回标记,重复输入

int jisuan ( float x, float y, float z, float w);              // a .b.c.d 的所有排列组合情况

jisuan(a,b,c,d); jisuan(a,b,d,c); jisuan(a,c,d,b);

jisuan(a,c,b,d); jisuan(a,d,b,c); jisuan(a,d,c,b);

jisuan(b,a,c,d); jisuan(b,a,d,c); jisuan(b,c,a,d);

jisuan(b,c,d,a); jisuan(b,d,c,a); jisuan(b,d,a,c);

jisuan(c,a,b,d); jisuan(c,a,d,b); jisuan(c,b,d,a);

jisuan(c,b,a,d); jisuan(c,d,a,b); jisuan(c,d,b,a);

jisuan(d,a,b,c); jisuan(d,a,c,b); jisuan(d,b,c,a);

jisuan(d,b,a,c); jisuan(d,c,a,b); jisuan(d,c,b,a);

return 0; }

int jisuan ( float x, float y, float z, float w)       //运算表达式的所有情况

{ if (x+y+z+w==24) cout<<x<<"+"<<y<<"+"<<z<<"+"<<w<<"=24"<<endl;

else if (x+y+z-w==24) cout<<x<<"+"<<y<<"+"<<z<<"-"<<w<<"=24"<<endl;

else if ((x+y)*(z+w)==24) cout<<"("<<x<<"+"<<y<<")*("<<z<<"+"<<w<<")=24"<<endl;

else if ((x-y)*(z+w)==24) cout<<"("<<x<<"-"<<y<<")*("<<z<<"+"<<w<<")=24"<<endl;

else if ((x-y)*(z-w)==24) cout<<"("<<x<<"-"<<y<<")*("<<z<<"-"<<w<<")=24"<<endl;

else if ((x+y+z)*w==24) cout<<"("<<x<<"+"<<y<<"+"<<z<<")*"<<w<<"=24"<<endl;

else if ((x-y-z)*w==24) cout<<"("<<x<<"-"<<y<<"-"<<z<<")*"<<w<<"=24"<<endl;

else if ((x+y-z)*w==24) cout<<"("<<x<<"+"<<y<<"-"<<z<<")*"<<w<<"=24"<<endl;

else if ((x*y*z)/w==24) cout<<"("<<x<<"*"<<y<<"*"<<z<<")/"<<w<<"=24"<<endl;

else if ((x*y)*(z+w)==24) cout<<"("<<x<<"*"<<y<<")*("<<z<<"+"<<w<<")=24"<<endl;

else if ((x*y)*(z-w)==24) cout<<"("<<x<<"*"<<y<<")*("<<z<<"-"<<w<<")=24"<<endl;

else if ((x*y)*z-w==24) cout<<"("<<x<<"*"<<y<<")*("<<z<<")-"<<w<<"=24"<<endl;

else if ((x*y)*z+w==24) cout<<"("<<x<<"*"<<y<<")*("<<z<<")+"<<w<<"=24"<<endl;

else if (x*y*z*w==24) cout<<x<<"*"<<y<<"*"<<z<<"*"<<w<<"=24"<<endl;

else if ((x+y)+(z/w)==24) cout<<"("<<x<<"+"<<y<<")+("<<z<<"/"<<w<<")"<<"=24"<<endl;

else if ((x+y)*(z/w)==24) cout<<"("<<x<<"+"<<y<<")*("<<z<<"/"<<w<<")"<<"=24"<<endl;

else if ((x*y)+z+w==24) cout<<"("<<x<<"*"<<y<<")+"<<z<<"+"<<w<<"=24"<<endl;

else if ((x*y)+z-w==24) cout<<"("<<x<<"*"<<y<<")+"<<z<<"-"<<w<<"=24"<<endl;

else if ((x*y)-(z/w)==24) cout<<"("<<x<<"*"<<y<<")-("<<z<<"/"<<w<<")"<<"=24"<<endl;

else if ((x*y)+(z/w)==24) cout<<"("<<x<<"*"<<y<<")-("<<z<<"/"<<w<<")"<<"=24"<<endl;

else if ((x*y)-z-w==24) cout<<"("<<x<<"*"<<y<<")-"<<z<<"-"<<w<<"=24"<<endl;

else if ((x*y)+(z*w)==24) cout<<"("<<x<<"*"<<y<<")+("<<z<<"*"<<w<<")"<<"=24"<<endl;

else if ((x*y)-(z*w)==24) cout<<"("<<x<<"*"<<y<<")-("<<z<<"*"<<w<<")"<<"=24"<<endl;

else if ((x*y)/(z*w)==24) cout<<"("<<x<<"*"<<y<<")/("<<z<<"*"<<w<<")"<<"=24"<<endl;

else if ((x*y)/(z-w)==24) cout<<"("<<x<<"*"<<y<<")/("<<z<<"-"<<w<<")"<<"=24"<<endl;

else if ((x*y)/(z+w)==24) cout<<"("<<x<<"*"<<y<<")/("<<z<<"+"<<w<<")"<<"=24"<<endl;

else cout<<"不可以组成24"<<endl;

return 0; }

算法二:

#include <iostream> 

#include <string> 

#include <math.h> 

using namespace std; 

const double LING = 1E-6; 

const int CONT = 4; 

const int VOLUE = 24; 

double number[CONT]; 

string biaodashi[CONT]; 

bool Panduan = false;                    //判断是否有解。

int count = 0;  

void Chazhao(int n) 

      if (n == 1)

  

            if ( fabs(number[0] - VOLUE) <= LING  

   {        

       cout << biaodashi[0] << "\t\t";

      Panduan = true;

      count ++;

      if((count % 3)==0) //使输出时每行三个表达式

       cout<<endl;

           

   else

   {  

      

       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 = biaodashi[i]; 

        expb = biaodashi[j]; 

        biaodashi[j] = biaodashi[n - 1];

         biaodashi[i]= '('+ expa + '+' + expb + ')'; 

         number[i] = a + b; 

         Chazhao(n-1);

         biaodashi[i]='('+ expa+ '-' + expb + ')';  

         number[i] = a - b; 

         Chazhao(n-1);  

         biaodashi[i] = '('+expb + '-' + expa + ')';  

         number[i] = b -a; 

         Chazhao(n-1);                                            

         biaodashi[i]= '('+ expa +'*'+ expb+ ')';  

         number[i]=a*b; 

         Chazhao(n-1); 

        if (b != 0)

      {

         biaodashi[i] ='('+expa+'/' + expb + ')';  

         number[i] = a / b; 

         Chazhao(n-1); 

       }   

        if (a != 0)

     

            biaodashi[i]='('+expb + '/'+ expa + ')';  

            number[i] = b / a; 

            Chazhao(n-1); 

     

       number[i] =a;        

       number[j]=b;        

       biaodashi[i] = expa;          

       biaodashi[j] = expb;         

               

    }

int main() 

 cout<<"请输入四个数:\n";

        for (int i = 0; i < CONT; i++)

 {

     char   ch[20];  

    cout<<""<<i+1<<"个数:";

                cin >>number[i];                 

                itoa(number[i],ch, 10);   //itoa()函数的作用是把第一个参数(数值)传送(转换)到第二个参数(字符串)中去,第三个参数(int)是该数值在字符串里以什么进制存放。

                biaodashi[i] = ch; 

        }

 cout<<endl;

 Chazhao(CONT) ;

 if(Panduan==true)

 { 

     cout   << "\n成功!" << endl;

    cout<<"总共的计算方法共有: "<<count<<endl;

       

 else

 { 

            cout << "失败!"   <<   endl; 

        }      

 return 0;

}

你可能感兴趣的:(关于24点游戏的编程思路与基本算法)