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)))
再给出另一种思路生成全排列,将每一个元素x插入到S−x的全排列的最前面 :
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∗[(k−1)!+T(k−1)]=N∗(k−1)!+NT(k−1)...(1) ,
而正常的的消耗是T(k)=T(k−1)+N∗(k−1)!.(2)
来计算一下(1) :
T(N)=N!+NT(N−1)=N!+N∗[(N−2)!+T(N−2)]
=N!+N∗(N−2)!+N[N∗(N−3)!+T(N−3)]
=N!+N∗(N−2)!+N2∗(N−3)!+N2[N∗(N−4)!+NT(N−4)]
=...+N3(N−4)!+N3T(N−4)=
N!+N∗(N−2)!+N2∗(N−3)!+.....NN−1≤NN
计算一下(2) :
T(N)=N!+N∗(N−2)!+N∗(N−3)!..=O(N!)
综上,错误的方式需要大约NNN!∗T 的时间。
补充练习 ,上面的方法虽然简洁,但是效率太低,算到N=9就很吃力了。下面给出一个高效且同样不复杂的办法:
进行DFS+剪枝,这里主要就是记录下已经占据了的行数,然后直从可用的行数里面进行挑选。
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
- SICP_Python第二章:映射(子集问题,排列问题,N皇后问题)
- 回溯问题+幂集、排列、子集和问题、八皇后问题
- 全排列问题与n皇后问题
- N*N皇后问题
- 子集和全排列问题
- 八皇后 n皇后 问题
- 八皇后N皇后问题
- C++ 输出全排列 简单递归 N皇后问题
- N皇后问题(回溯VS全排列)
- N皇后问题
- n皇后问题
- N皇后问题
- N 皇后问题
- N皇后问题
- N皇后问题算法
- N 皇后问题
- N皇后问题
- N皇后问题
- Balanced Binary Tree
- [Splay模拟 线段树 || Splay || LCT] HDU 4942 Game on S♂play
- Codeforces 405B Domino Effect
- JSP及相关技术知识总结
- NYOJ-2括号配对问题
- SICP_Python第二章:映射(子集问题,排列问题,N皇后问题)
- React JSX,应如何配置Emacs
- stm32 知识点
- node package有两种依赖
- ListView的Item上有Button按钮,点击执行单个Item删除动画
- 关于Java的List的笔记
- [C++]高效使用关联容器的一些建议
- django haystack update_index 实现自动化 同步
- jQuery学习之jQuery Ajax用法详解