SICP_Python第二章:映射(子集问题,排列问题,N皇后问题)

来源:互联网 发布:控制算法工程师招聘 编辑:程序博客网 时间:2024/05/14 06:17

下面是自己实现的map方法。

def simple_map(proc,items):    result = []    for item in items:        result.append(proc(item))    return resultdef scale_list(items,factor):    return simple_map(lambda x:x*factor,items)print(scale_list([1,2,3,4,5,6],5))

2.21 返回每个数的平方构成的表:

def square_list(items):    return simple_map(lambda x:x**2,items)print(square_list(range(9)))

2.29此题有一点难度。

def make_mobile(left,right):    return (left,right)def make_branch(length,structure):    return (length,structure)def left_branch(t):    return getitem(t,0)def right_branch(t):    return getitem(t,1)def branch_length(branch):    return getitem(branch,0)def branch_structure(branch):    return getitem(branch,1)def total_weight(t):    if type(t)==type(1):        return t    return total_weight(branch_structure(left_branch(t)))+total_weight(branch_structure(right_branch(t)))def is_balanced(t):    if type(t)==type(1):return True,t    ok1,w1 = is_balanced(branch_structure(left_branch(t)))    ok2,w2 = is_balanced(branch_structure(right_branch(t)))    ok3 = branch_length(left_branch(t))*w1==branch_length(right_branch(t))*w2    return ok1&ok2&ok3,w1+w2T = ((8,((1,12),(3,4))),(16,((1,6),(3,2))))print(is_balanced(T))

2.32,返回一个集合所有子集的集合。

这道题的代码虽短,但是还是需要思考一下的。注意到,当前集合所有元素的子集可以通过除第一个元素以外的剩余集合的所有集合子集设为rest,则rest+rest(first)就是完整的子集集合,rest(first)等价于每一个元素都添加上first。

def restof(s):    return s[1:]def firstof(s):    return s[0]def transform(x):    if type(x)==type(1):return (x,)    return xdef subsets(s):    print(s)    if s==():return((),)    first = firstof(s)    rest = subsets(restof(s))    u = rest+tuple(map(lambda x:transform(x)+(first,),rest))    return u

提供一种非递归的思路,虽然相对较慢,但是避免了递归层数的限制。采取BFS遍历状态。

def combinations(s):    n = len(s)    q,conditions=deque(),{():n}    if n==0:return None    q.append(())    size_q = 1    while size_q:        case = q.pop()        size = conditions[case]        if size:            item = s[n-size]            u = case+(item,)            q.append(u)            q.append(case)            conditions[u],conditions[case] = size-1,size-1            size_q+=1        else:            size_q-=1            print(case)

n(j,i)1=<j<i<=n,i+j

这里就体现了嵌套映射的威力,和书上的方法不一样,计算一个数是不是素数的开销较大,因此先计算出2-2n-1的素数,然后计算每一个数的序对,最后将这些序对累积到一起。这里面就使用了两层映射的结合加过滤。代码很少就解决了问题。

def flat_map(proc,seq):    return reduce(lambda x,y:x+y if type(x)==type([]) else [x]+y  ,map(proc,seq))#map the second time and accumulatedef prime_sum_pairs(n):    def f(x):        jmax = ((x-1)//2) +1        return [(j,x-j) for j in range(max(1,x-n),jmax)]#map the first time    seq = [x for x in range(2,2*n) if is_prime(x)]    return flat_map(f,seq)

2.40:类似上面的结构:

def unique_pairs(n):    return flat_map(lambda x:[(j,x-j) for j in range(max(1,x-n),((x-1)//2) +1)],range(3,n*2))

:生成一个集合的全排列

基本思路是:将第一个元素first插入到剩下元素的全排列的每一个位置。

def permutation(sets):    def rest(s):return s[1::]    def create_subsets(s):        nonlocal first        return [tuple(range(l+1))for index in range(len(s)+1)]    if sets==():return [()]    first = sets[0]    return flat_map(create_subsets,permutation(rest(sets)))print(permutation((1,2,3,4)))

,xSx:

def permutation(sets):    def rest(x):return tuple([item for item in sets if item!=x])    def f(x):return [tuple([x]+list(each)) for each in permutation(rest(x))]    if sets==():return [()]    return flat_map(f,sets)

对比两种思路:虽然简洁其实都不高效。。。具体的分析请看该链接…

2.41

def create_pairs(s,n):    for i in range(1,s+1):        for j in range(i+1,s+1):            k = s-(i+j)            if k <= j:break            print((i,j,k))

2.42 10行代码就解决了8皇后问题,但是这个逻辑相对不太容易看明白,因为程序写的十分紧凑而且效率比较低下。

def queens(size):    def queen_cols(k):        def safe(item):            n = len(item)//2            rows = set([x for (i,x) in enumerate(item) if i%2==0 ])            cols = set([x for (i,x) in enumerate(item) if i%2==1 ])            return len(rows)==n and len(cols)==n        if k==size+1:return [tuple()]        rest = queen_cols(k+1)        return list(filter(safe,flat_map(lambda row:[(row,k)+each for each in rest],range(1,size+1))))    return queen_cols(1)

2.43我一开始就犯了这个错误,按照书上的写法,每一次内层映射都会去求一次rest_of_queens,相当于T(k)=N[(k1)!+T(k1)]=N(k1)!+NT(k1)...(1),

而正常的的消耗是T(k)=T(k1)+N(k1)!.(2)

来计算一下(1)

T(N)=N!+NT(N1)=N!+N[(N2)!+T(N2)]

=N!+N(N2)!+N[N(N3)!+T(N3)]

=N!+N(N2)!+N2(N3)!+N2[N(N4)!+NT(N4)]

=...+N3(N4)!+N3T(N4)=

N!+N(N2)!+N2(N3)!+.....NN1NN

计算一下(2):

T(N)=N!+N(N2)!+N(N3)!..=O(N!)

综上,错误的方式需要大约NNN!T的时间。

,上面的方法虽然简洁,但是效率太低,算到N=9就很吃力了。下面给出一个高效且同样不复杂的办法:

进行DFS+剪枝,这里主要就是记录下已经占据了的行数,然后直从可用的行数里面进行挑选。

T(N)=N!

def quick_queens(size):    av_rows = list(range(1,size+1))    Final_pos = [()]    def quick_cols(k,case):        nonlocal Final_pos        nonlocal av_rows        if k==size+1:Final_pos.append(case)        t = av_rows[::]        for i in t:            av_rows.remove(i)            quick_cols(k+1,case+(i,k))            av_rows.append(i)    quick_cols(1,())    return Final_pos

规律总结,其实N皇后问题的解就是一个全排列而已。

0 0
原创粉丝点击