一个算24点的算法

  最近,我用Lua写了一个算24点的算法,这个算法的思想很简单,就是不断穷举表达式,然后计算每个表达式的值是否为24。如果为24,则输出。问题的难点在于如何穷举表达式,我的做法是将要处理的数和另外穷举出的运算符组成一个含有七个元素的数组(四个操作数,三个操作符),然后遍历这个数据的全排列,将每个排列看成一个逆波兰式,如果计算成功,则将逆波兰式再转成中辍表达式输出。这个算法有一个明显的缺点,它会产生很多冗余的式子(即形式不同,但运算实质相同)。

  1. #!/usr/bin/env lua
  2.  
  3. -- used for store four points
  4. array={}
  5.  
  6. -- reverse the whole array from first to last
  7. function array.reverse(this,first,last)
  8.         first = first or 1
  9.         last = last or table.maxn(this)
  10.         while first < last do
  11.                 this[first],this[last]=this[last],this[first]
  12.                 first=first+1
  13.                 last=last-1
  14.         end
  15. end
  16.  
  17. -- this algorithm is modified from the C++ STL
  18. -- change array to next permutation and returns true
  19. -- return false if the current is the last permutation
  20. function array.next_permutation(this,first,last)
  21.         local len=table.maxn(this)
  22.         if len==0 or len==1  then
  23.                 return false
  24.         end
  25.  
  26.         first = first or 1
  27.         last = last or len
  28.        
  29.         local i=last
  30.         while true do
  31.                 local ii=i
  32.                 i=i-1
  33.                 if this[i] < this[ii] then
  34.                         local j=last
  35.                         while this[i] >= this[j] do
  36.                                 j=j-1
  37.                         end
  38.                         this[i],this[j]=this[j],this[i]
  39.                         this:reverse(ii,last)
  40.                         return true
  41.                 end
  42.  
  43.                 if i==first then
  44.                         return false
  45.                 end
  46.         end
  47. end
  48.  
  49. -- show the array with space seperated
  50. function array.show(this)
  51.         for _,i in ipairs(this) do
  52.                 io.write(i,' ')
  53.         end
  54.         io.write('\n')
  55. end
  56.  
  57. optable={"+","-","*","/"}
  58. opfuncs={}
  59. opfuncs["+"]=function(a,b)
  60.         return a+b
  61. end
  62.  
  63. opfuncs["-"]=function(a,b)
  64.         return a-b
  65. end
  66.  
  67. opfuncs["*"]=function(a,b)
  68.         return a*b
  69. end
  70.  
  71. opfuncs["/"]=function(a,b)
  72.         if b==0 then
  73.                 return nil
  74.         else
  75.                 return a/b
  76.         end
  77. end
  78.  
  79.  
  80. -- stack class for calculation
  81. function Stack()
  82.         local stack={}
  83.         stack.push=table.insert
  84.         stack.pop=table.remove
  85.         stack.size=table.maxn
  86.         stack.bottom=function(this)
  87.                 return this[1]
  88.         end
  89.         return stack
  90. end
  91.  
  92. -- calculate from polish notation
  93. function array.eval(toeval)
  94.         local stack=Stack()
  95.         for _,v in ipairs(toeval) do
  96.                 local op=opfuncs[v]
  97.                 if op then
  98.                         if stack:size() <2 then
  99.                                 return nil
  100.                         end
  101.                         local b=stack:pop()
  102.                         local a=stack:pop()
  103.                         local result=op(a,b)
  104.                         if result then
  105.                                 stack:push(result)
  106.                         else
  107.                                 return nil
  108.                         end
  109.                 else
  110.                         stack:push(tonumber(v))
  111.                 end
  112.         end
  113.  
  114.         return stack:bottom()
  115. end
  116.  
  117. -- precedence table, "n" is number
  118. precedence={
  119.         ["+"] = 1;
  120.         ["-"] = 1;
  121.         ["*"] = 2;
  122.         ["/"] = 2;
  123.         ["n"] = 3;
  124. }
  125.  
  126. -- convert from polish expression to normal expression
  127. function array.show_expr(this)
  128.         local strStack=Stack()
  129.         local typeStack=Stack()
  130.        
  131.         for _,v in ipairs(this) do
  132.                 if opfuncs[v] then
  133.                         local b=strStack:pop()
  134.                         local a=strStack:pop()
  135.  
  136.                         local bp=precedence[typeStack:pop()]
  137.                         local ap=precedence[typeStack:pop()]
  138.                         local vp=precedence[v]
  139.                        
  140.                         if ap<=vp then
  141.                                 a="("..a..")"
  142.                         end
  143.  
  144.                         if bp<=vp then
  145.                                 b="("..b..")"
  146.                         end
  147.  
  148.                         strStack:push(a..v..b)
  149.                         typeStack:push(v)
  150.                 else
  151.                         strStack:push(v)
  152.                         typeStack:push("n")
  153.                 end
  154.         end
  155.         print(strStack:bottom())
  156. end
  157.  
  158.  
  159. -- get table copy(contains its methods)
  160. function array.copy(this)
  161.         local copy={}
  162.         for index,value in pairs(this) do
  163.                 copy[index]=value
  164.         end
  165.         return copy
  166. end
  167.  
  168. -- the main method to calculate 24 points
  169. function array.calc(this)
  170.         local order=1
  171.         for i=1,4 do
  172.                 for j=i,4 do
  173.                         for k=j,4 do
  174.                                 local toeval=this:copy()
  175.                                 table.insert(toeval,optable[i])
  176.                                 table.insert(toeval,optable[j])
  177.                                 table.insert(toeval,optable[k])
  178.                                 table.sort(toeval)                       
  179.                                 while true do
  180.                                         if tostring(toeval:eval())=="24" then
  181.                                                 io.write(order,": ")
  182.                                                 toeval:show_expr()
  183.                                                 order=order+1
  184.                                         end
  185.  
  186.                                         if not toeval:next_permutation() then
  187.                                                 break
  188.                                         end
  189.                                 end
  190.                         end
  191.                 end
  192.         end
  193. end
  194.  
  195. for i=1,4 do
  196.         if not arg[i] then
  197.                 io.stderr:write("Please input at least four arguments!\n")
  198.                 return 1
  199.         end
  200.  
  201.         local num=tonumber(arg[i])
  202.         if not num then
  203.                 io.stderr:write("Arguments must be numbers\n")
  204.                 return 2
  205.         end
  206.        
  207.         if num<1 or num > 13 then
  208.                 io.stderr:write("Number must in [1,13]\n")
  209.                 return 3
  210.         end
  211.  
  212.         if math.floor(num)~=num then
  213.                 io.stderr:write("Number must be an integer!\n")
  214.                 return 4
  215.         end
  216.  
  217.         table.insert(array,arg[i])
  218. end
  219.  
  220. array:calc()
  1.  
  2.  

     

Algorithm Comments(0) 2008年6月28日 14:13