Way,Method,Algorithm  
算法的世界
日历
<2006年12月>
262728293012
3456789
10111213141516
17181920212223
24252627282930
31123456
统计
  • 随笔 - 5
  • 文章 - 4
  • 评论 - 10
  • 引用 - 0

导航

常用链接

留言簿(2)

随笔分类

随笔档案

文章分类

文章档案

搜索

  •  

最新评论

阅读排行榜

评论排行榜

 

24点算法代码(C语言版本):
int Search(int n, int iGroup)
{
      /*~~~~~~~~~~*/
      int  i, j;
      double a, b;
      char expa[MAX_LENGTH_OF_EXP];
      char expb[MAX_LENGTH_OF_EXP];
      /*~~~~~~~~~~*/
      if(1 == n)
      {
              if(fabs(number[iGroup][0] - NUMBER_TO_BE_CAL) < PRECISION)
              {
                     return 1;
              }
              else
              {
                     return 0;
              }
       }
       for(i = 0; i < n; i++)
       {
           for(j = i + 1; j < n; j++)
           {
               strcpy(expa, expression[i]);
               strcpy(expb, expression[j]);
               a = number[iGroup][i];
               b = number[iGroup][j];
            
               number[iGroup][j] = number[iGroup][n - 1];
               strcpy(expression[j], expression[n - 1]);

               sprintf(expression[i], "(%s+%s)", expa, expb);
               number[iGroup][i] = a + b;
            
               if(Search(n - 1, iGroup))
               {
                   return 1;
               }

               sprintf(expression[i], "(%s-%s)", expa, expb);
               number[iGroup][i] = a - b;
               if(Search(n - 1, iGroup))
               {
                   return 1;
               }

               sprintf(expression[i], "(%s-%s)", expb, expa);
               number[iGroup][i] = b - a;
               if(Search(n - 1, iGroup))
               {
                   return 1;
               }

               sprintf(expression[i], "(%s*%s)", expa, expb);
               number[iGroup][i] = a * b;
               if(Search(n - 1, iGroup))
               {
                   return 1;
               }

               if(b != 0)
               {
                   sprintf(expression[i], "(%s/%s)", expa, expb);
                   number[iGroup][i] = a / b;
                   if(Search(n - 1, iGroup))
                   {
                       return 1;
                   }
               }

               if(a != 0)
               {
                   sprintf(expression[i], "(%s/%s)", expb, expa);
                   number[iGroup][i] = b / a;
                   if(Search(n - 1, iGroup))
                   {
                       return 1;
                   }
               }

               number[iGroup][i] = a;
               number[iGroup][j] = b;
               strcpy(expression[i], expa);
               strcpy(expression[j], expb);
           }
       }
 return 0;
}

基本原理
基本原理是穷举4个整数所有可能的表达式,然后对表达式求值。

表达式的定义: expression = (expression|number) operator (expression|number)

因为能使用的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 则恢复数组,以确保当前递归调用获得下一个正确的排列。

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


程序中比较重要的地方解释如下:
 (1) int Search(int, int) 就是递归函数. char expression[][] 存放每一步产生的表达式,最后的输出中要用到。
 expression[][] 与 number[][] 类似,也是递归调用的现场,必须在下一层递归调用前改变、在下一层递归调用后恢复。
 
 (2) number[][] 数组长度只有4。 在 Search() 中,每次取出两个数后,使用局部变量 a, b 保存这两个数,
 同时数组中加入运算结果,并调整数组使得有效的数字都排列在数组前面。
 在下一层递归调用后,利用局部变量a, b 恢复整个数组。对 expression[][] 的处理与 number[][] 类似。
 
 (3) 因为 + * 满足交换率而 - / 不满足,所以程序中,从数组生成两个数的排列,
 for (i = 0; i < n; i++) {
   for (j = i + 1; j < n; j++) {
 其内层循环 j 是从 i+1 -> n,而非从 0->n,因为对于交换率来说,两个数字的顺序是无所谓的。
 当然,循环内部对 - / 做了特殊处理,计算了 a-b b-a a/b b/a 四种情况。
 
 (4) 此程序只求出第一个解。当求出第一个解时,通过层层 return true 返回并输出结果,然后程序结束。
 
 (5) 以 double 来进行求解,定义精度,用以判断是否为 24 。考虑 (5-1/5)*5 这个表达式就知道这么做的原因了。
 
 (devil) 输出时,为每个表达式都添加了括号。

(6)  输出时,为每个表达式都添加了括号。

posted on 2006-12-19 20:45 Whale 阅读(3472) 评论(3)  编辑 收藏 引用 所属分类: 思想火花
评论:
  • # re: 24点递归算法及C语言代码【网上收集】  Whale Posted @ 2006-12-20 18:19
    Step1:最后一次肯定是两个数进行+、-、*、/的遍历(-和/要注意先后顺序)
    Step2:最后两个数字从哪来?
    如果是第一次调用,任取三个数全做第一种运算(程序中为“+”)得到一个结果;如果不是第一次调用,根据传入的两个数(可能由Step7传入),另外再任取一个数做第一种运算;把这个结果和四个数中剩余的那个数,有了这两个数,转入Step1;
    如果没有得到结果转入step3;
    Step3:到此,说明上述step1中的参与运算的数字不对,考虑到step1中的两个运算数,一个是组合运算数和另一个是单一数参与,所以修改组合运算数。
    Step4:如何修改组合运算数?
    固定Step2中三个数的前两个数,这两个数仍然只做Step2中它们所做的运算,通过把这个运算结果和
    4.1.a) Step2中三个数中剩下的那个数根据step1得到一个结果
    (或者)
    4.1.b) Step2中没有选定的那个数根据step1得到一个结果
    到此,达到了修改参与运算数的目的。
    4.2) 有了这个结果和四个数中剩余的另外一个数又可以转到Step1;
    如果不能得到结果,转入step5:
    (注意:我们到此也就发现了算法的重复计算,比如之前运算过((4+5)+7)+6),现在还有可能要运算(((4+5)+6)+7))
    Step5:到此,说明除了Step4中固定的两个数外,剩下的两个数不能作为个体参与运算,
    于是:
    5.1) 剩余的两个数做step1,得到一个结果
    5.2) 把Step5.1中的这个结果和Step4中固定的两个数的运算结果做Step1;
    如果不能得到结果,转入step6;
    Step6:到此,说明前两个数固定的数不能只用Step4中的运算方法运算得到,
    于是:对固定的两个数用Step1;将计算结果转到Step4;
    如果没有得到结果转入step7;
    Step7: 到此,说明Step4中固定的两个数字有误,固定Step4中的第一个数字,选取不是Step4中固定的另外两个数根据Step1,转入Step2;
      回复  更多评论   

  • # re: 24点递归算法及C语言代码【网上收集】   Posted @ 2008-07-02 16:20
    81个错误
      回复  更多评论   

  • # re: 24点递归算法及C语言代码【网上收集】  大笨兔 Posted @ 2012-07-03 11:39
    转载说明:本资源来源于[异域世界网www.yangli89.lingd.net]
    若需转载,请保留资源的相关链接及信息,相关内容如下:

    我的方法差不多,不过我的是直接求结果。
    一般的结果是没有问题的,不过由于浮点数的一些限制,一些答案不能计算出来。
    比如我
    float num1,num2;
    num1 = 1.0;num2 = 5.0;
    比较一下(1.0/5.0) == num1/num2;
    我K,他们不相等。就是这里影响了程序的正确性
    所以我还要想其他的办法


    本资源来源于[异域世界网www.yangli89.lingd.net]
    资源链接:http://yangli89.lingd.net/article-4110044-1.html  回复  更多评论   


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理


 
Copyright © Whale Powered by: 博客园 模板提供:沪江博客