`
realfun
  • 浏览: 25317 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

猜数字游戏8步以内的完全求解决策树生成程序

阅读更多
Python代码 : 猜数字游戏8步以内的完全求解决策树生成程序
001 #coding=utf-8
002
003 #猜数字游戏8步以内的求解决策树生成程序
004 #    解题思路与一步步的解题程序参见:
005 #       http://www.fayaa.com/code/view/116/
006 #
007
008 #使用方法:
009 # 1. 保存代码为guessall.py
010 # 2. 执行python guessall.py > result.txt
011 # 3. 打开result.txt看结果
012
013 #为了可读性和简单性使用了列表推导,其他方法参见:
014 #  http://www.fayaa.com/code/view/114/
015 #  http://www.fayaa.com/code/view/118/
016 def init_set ():
017     r10 = range ( 10 )
018     return [( i , j , k , l )
019             for i in r10 for j in r10 for k in r10 for l in r10
020             if ( i != j and i != k and i != l and j != k and j != l and k != l ) ]
021
022 #对给定的两组数,计算xAyB
023 #不知道能不能更快些
024 def get_match_ab ( target , source ):
025     la , lb = 0 , 0
026     for ( i , t ) in enumerate ( target ):
027         for ( j , s ) in enumerate ( source ):
028             if s == t :
029                 if i == j :
030                     la += 1
031                 else :
032                     lb += 1
033                 #break this loop since we already found match
034                 break
035     return ( la , lb )
036
037 #by lancer
038 #思路很好,把原来的16次比较变成了8次
039 #经过timeit验证确实速度有所提高
040 def get_match_ab2 ( target , source ):
041     table = [ - 1 ] * 10
042     la , lb = 0 , 0
043     for i in xrange ( len ( source )):
044         table [ source [ i ]] = i
045     for i in xrange ( len ( target )):
046         if table [ target [ i ]] == i :
047             la += 1
048         elif table [ target [ i ]] != - 1 :
049             lb += 1
050     return ( la , lb )
051
052 #nums: the number_set list to be checked
053 #guess: last guess
054 #a, b: the number of aAbB
055 #@return: the rest number_sets which matche last guess
056 def check_and_remove ( nums , guess , a , b ):
057     rest_nums = []
058     for num_set in nums :
059         if ( a , b ) == get_match_ab ( num_set , guess ):
060             rest_nums . append ( num_set )
061     return rest_nums
062
063 #计算在nums中选择target以后,所有ab分支里面的剩余组合个数
064 def calc_ab_counts ( target , nums ):
065     #a * 10 + b is used to indicate an "a & b" combination
066     ab_map = {}
067     #init ab_map
068     abs = ( 0 , 1 , 2 , 3 , 4 , 10 , 11 , 12 , 13 , 20 , 21 , 22 , 30 , 31 , 40 )
069     for ab in abs :
070         ab_map [ ab ] = 0
071     #let's do the calculation
072     for num_set in nums :
073         ( a , b ) = get_match_ab ( num_set , target )
074         ab_map [ a * 10 + b ] += 1
075     return [ ab_map [ ab ] for ab in abs ]
076
077 #计算一个选择相对于选择集的“标准差”
078 def calc_standard_deviation ( target , nums ):
079     ab_counts = calc_ab_counts ( target , nums )
080     total = sum ( ab_counts )
081     avg = float ( total ) / len ( ab_counts )
082     sd = sum ([( abc - avg ) ** 2 for abc in ab_counts ])
083     return sd
084
085 #根据现有集合寻找下一个集合
086 #采用“最小标准差”作为衡量标准
087 def next_guess ( nums ):
088     min_sd = 0
089     min_set = ()
090     touched = False
091     for num_set in nums :
092         sd = calc_standard_deviation ( num_set , nums )
093         if not touched or min_sd > sd :
094             touched = True
095             min_set = num_set
096             min_sd = sd
097     return min_set
098
099 #根据现有集合寻找下一个集合
100 #随机选取,会有4-5个超过八次
101 def next_guess2 ( nums ):
102     return nums [ 0 ]
103
104 #折衷的方法:小于500用最小标准差
105 def next_guess3 ( nums ):
106     if len ( nums ) > 500 :
107         return next_guess2 ( nums )
108     else :
109         return next_guess ( nums )
110
111 #计算熵
112 import math
113 def calc_entropy ( target , nums ):
114     ab_counts = calc_ab_counts ( target , nums )
115     total = sum ( ab_counts )
116     hs = []
117     for abc in ab_counts :
118         h = 0
119         if abc :
120             p = float ( abc ) / total
121             h = p * math . log ( p , 2 )
122         hs . append ( h )
123     return sum ( hs )
124
125 #使用信息量作为衡量标准
126 def next_guess4 ( nums ):
127     min_sd = 0
128     min_set = ()
129     touched = False
130     for num_set in nums :
131         sd = calc_entropy ( num_set , nums )
132         if not touched or min_sd > sd :
133             touched = True
134             min_set = num_set
135             min_sd = sd
136     return min_set
137
138 #决策树生成思路
139 #1. 生成所有的四位0-9数字组合,用0123做初始选择,空列表queue=[], result={}
140 #   result: (当前选择, {21:(下一个选择, {})}, 13:abcd<最终结果值>, ...})
141 #   queue: [(rest_nums, 对应当前猜测状态的result节点), ...]
142
2
1
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics