1. 递归回溯
在n个元素中选择m个,对于每个元素来说都可以有选择与不选择两种状态,很容易构造一个高度为n的状态数。
s = raw_input('enter n, m:').split()
n,m = int(s[0]),int(s[1])
data = [i for i in range(n)]
sel = [0]*n
def print_comb(data,sel,n):
for i in range(n):
if sel[i]==1:
print data[i],
print ''
def comb_dfs(data, sel, n, m, cur=0):
if m==0:
print_comb(data,sel,n)
return
if cur>=n or m < 0:
return
#选
sel[cur] = 1
comb_dfs(data,sel,n,m-1,cur+1)
#不选
sel[cur] = 0
comb_dfs(data,sel,n,m,cur+1)
2. 非递归–字典序
对于[‘a’, ‘b’, ‘c’, ‘d’]选择3个元素,它有6种结果,1表示选择,0表示不选择,并把01序列看成2进制数,则结果为: 1100,ab,3(高位在后) 1010,ac,5 0110,bc,6 1001,ad,9 0101,bd,10 0011,cd,12 可以看出每个组合构成了一个有序的序列,初始序列是优先选择左边的元素,即把3个1放到最左边。终止条件是所有的1放到右边,如0111。问题是给定任意一个组合,如何得到它的下一个组合。比如给定0110(bc),得到1001(ad)的步骤为: 1. 从左往右扫描,找到第一个10,将1的位置记录为q,将10反转,得0101 2. 将0到q-1序列里面的1全部提到最左边,得1001。
def comb(data,n,m):
sel = [1]*m
for i in range(m,n):
sel.append(0)
print_comb(data,sel,n)
while True:
one_zero_ids = -1
one_nums = 0
for i in range(n):
if sel[i] == 1:
one_nums += 1
one_zero_ids = i
elif sel[i] == 0 and one_zero_ids != -1:
break
if one_zero_ids == -1 or one_zero_ids == n-1:
break
sel[one_zero_ids],sel[one_zero_ids+1] = sel[one_zero_ids+1],sel[one_zero_ids]
for i in range(one_nums-1):
sel[i] = 1
for i in range(one_nums-1,one_zero_ids):
sel[i] = 0
print_comb(data,sel,n)