backtracking
Permutation순열의 성질중 아래 같은 성질을 이용해서 코딩을 한다.
아래 성질을 말로 풀면, (n-1)개에 대한 조합들이 있고, 그 조합에서 1개를 그 사이에 집어넣을 수 있는데, 그 경우의 수가 n 개이다.
def perms(elements):
if len(elements) ==1:
# yield elements
return [elements]
else:
ret = []
for perm in perms(elements[1:]):
for i in range(len(elements)):
# 한개를 정하고, 그 한개 이외의 값들을 permutation 을 하고,
# 그 한개의 위치만 바꾼다.
# nb elements[0:1] works in both string and list contexts
# yield perm[:i] + elements[0:1] + perm[i:]
ret.append(perm[:i] + elements[0:1] + perm[i:])
return perm
perms([1,2,3])
return of perms() | perm | elements | i | elements[0:1] |
perm[:i] + elements[0:1] + perm[i:] |
---|---|---|---|---|---|
[[3]] |
[3] |
[2,3] |
0 | [2] |
[2,3] |
[[3]] |
[3] |
[2,3] |
1 | [2] |
[3,2] |
[[2, 3], [3, 2]] |
[2,3] |
[1,2,3] |
0 | [1] |
[1,2,3] |
[[2, 3], [3, 2]] |
[2,3] |
[1,2,3] |
1 | [1] |
[2,1,3] |
[[2, 3], [3, 2]] |
[2,3] |
[1,2,3] |
2 | [1] |
[2,3,1] |
[[2, 3], [3, 2]] |
[3,2] |
[1,2,3] |
0 | [1] |
[1,3,2] |
[[2, 3], [3, 2]] |
[3,2] |
[1,2,3] |
1 | [1] |
[3,1,2] |
[[2, 3], [3, 2]] |
[3,2] |
[1,2,3] |
2 | [1] |
[3,2,1] |
Combinations
순착적으로만 선택하면 된다.
먼저 조합(combination)의 성질을 조금 알 필요가 있다. combination은1,3
/ 3,1
을 같은 선택으로 본다. 그렇기 때문에 만약 다음처럼 elements 가 있다고 한다면,elements = [1,2,3]
우리가 앞에서 부터 순차적으로 선택한다면, 마지막 element 인 3을 선택한 이후에, 그 이전 element 를 선택할 필요가 없다. 즉,
1,3
을 선택했다면, 그 다음 2 를 선택해서, 1,3,2
를 선택할 필요가 없다. 왜냐하면, 이것은 1,2,3
에서 이미 만들어진 조합이기 때문이다.여기서 명심할 것은 다음에 나오는 코드의 주 내용은 가능한 모든 combination 을 찾아주는 방법이지, combination 이 몇개인지를 나타내는 것이 아니다.
recursive version
nCrans = [] def backtracking(path, elements, r): if r == 0: ans.append(list(path)) # copy is needed return for index, num in enumerate(elements): path.append(num) # choose, 선택 backtracking(path, elements[index + 1:], r - 1) path.pop() # unchoose, 선택해제 backtracking([], [1,2,3], 2)
combinations_with_replacement
ref. 2에 combination python source 가 있다.`i` 가 현재보고 있는 '자리'가 된다.
각 '자리'에 index 를 써놓는다.
가장 뒷 '자리' 부터 거꾸로 보는데,
그 '자리' 에 있는 index 가 마지막 index가 될 때까지, 보고있는 '자리'를 옮기지 않는다.
마지막 index 가 되면, 보고있는 '자리'를 한자리 앞으로 옮긴다.
'자리' 변경시
현재 보고 있는 '자리' 부터 뒷자리를, 현재 보고있는 '자리'의 index 값보다 +1 한 index 값으로 채운다.
1,1 1,2 1,3 2,1 ==> 1,2와 같다 2,2 2,3이렇게 순서대로 가야 하는데, 이것은 조합(combination) 이라서
1,2 == 2,1
이 같다. 그래서 새로운 '자리'에 값을 증가 시킬때는 이미 지나온 '자리'에는 새로운 '자리'의 값보다 작은 값을 넣을 필요가 없다.그래서 아래같은 code 를 사용한다.
indices[i:] = [indices[i] + 1] * (r - i)
def combinations_with_replacement(iterable, r): # combinations_with_replacement('ABC', 2) --> AA AB AC BB BC CC pool = tuple(iterable) n = len(pool) if not n and r: return ret = [] indices = [0] * r # yield tuple(pool[i] for i in indices) ret.append(tuple(pool[i] for i in indices)) while True: for i in reversed(range(r)): if indices[i] != n - 1: break else: return indices[i:] = [indices[i] + 1] * (r - i) # yield tuple(pool[i] for i in indices) ret.append(tuple(pool[i] for i in indices))
combinations_with_replacement([4,5,6,7], 3)
indices |
indices | r | i | r-i | indices[i] | n-1 | indices[i:] | [indices[i] + 1] * (r - i) | return |
---|---|---|---|---|---|---|---|---|
[0, 0, 0] | 3 | i=2 | 1 | 0 | 3 | [0] | [1] | [(4, 4, 4)] |
[0, 0, 1] | 3 | i=2 | 1 | 1 | 3 | [1] | [2] | [(4, 4, 4), (4, 4, 5)] |
[0, 0, 2] | 3 | i=2 | 1 | 2 | 3 | [2] | [3] | [(4, 4, 4), (4, 4, 5), (4, 4, 6)] |
[0, 0, 3] | 3 | i=1 | 2 | 0 | 3 | [0, 3] | [1, 1] | [(4, 4, 4), (4, 4, 5), (4, 4, 6), (4, 4, 7)] |
[0, 1, 1] | 3 | i=2 | 1 | 1 | 3 | [1] | [2] | [(4, 4, 4), (4, 4, 5), (4, 4, 6), (4, 4, 7), (4, 5, 5)] |
[0, 1, 2] | 3 | i=2 | 1 | 2 | 3 | [2] | [3] | [(4, 4, 4), (4, 4, 5), (4, 4, 6), (4, 4, 7), (4, 5, 5), (4, 5, 6)] |
[0, 1, 3] | 3 | i=1 | 2 | 1 | 3 | [1, 3] | [2, 2] | [(4, 4, 4), (4, 4, 5), (4, 4, 6), (4, 4, 7), (4, 5, 5), (4, 5, 6), (4, 5, 7)] |
[0, 2, 2] | 3 | i=2 | 1 | 2 | 3 | [2] | [3] | [(4, 4, 4), (4, 4, 5), (4, 4, 6), (4, 4, 7), (4, 5, 5), (4, 5, 6), (4, 5, 7), (4, 6, 6)] |
[0, 2, 3] | 3 | i=1 | 2 | 2 | 3 | [2, 3] | [3, 3] | [(4, 4, 4), (4, 4, 5), (4, 4, 6), (4, 4, 7), (4, 5, 5), (4, 5, 6), (4, 5, 7), (4, 6, 6), (4, 6, 7)] |
[0, 3, 3] | 3 | i=0 | 3 | 0 | 3 | [0, 3, 3] | [1, 1, 1] | [(4, 4, 4), (4, 4, 5), (4, 4, 6), (4, 4, 7), (4, 5, 5), (4, 5, 6), (4, 5, 7), (4, 6, 6), (4, 6, 7), (4, 7, 7)] |
[1, 1, 1] | 3 | i=2 | 1 | 1 | 3 | [1] | [2] | [(4, 4, 4), (4, 4, 5), (4, 4, 6), (4, 4, 7), (4, 5, 5), (4, 5, 6), (4, 5, 7), (4, 6, 6), (4, 6, 7), (4, 7, 7), (5, 5, 5)] |
[1, 1, 2] | 3 | i=2 | 1 | 2 | 3 | [2] | [3] | [(4, 4, 4), (4, 4, 5), (4, 4, 6), (4, 4, 7), (4, 5, 5), (4, 5, 6), (4, 5, 7), (4, 6, 6), (4, 6, 7), (4, 7, 7), (5, 5, 5), (5, 5, 6)] |
[1, 1, 3] | 3 | i=1 | 2 | 1 | 3 | [1, 3] | [2, 2] | [(4, 4, 4), (4, 4, 5), (4, 4, 6), (4, 4, 7), (4, 5, 5), (4, 5, 6), (4, 5, 7), (4, 6, 6), (4, 6, 7), (4, 7, 7), (5, 5, 5), (5, 5, 6), (5, 5, 7)] |
[1, 2, 2] | 3 | i=2 | 1 | 2 | 3 | [2] | [3] | [(4, 4, 4), (4, 4, 5), (4, 4, 6), (4, 4, 7), (4, 5, 5), (4, 5, 6), (4, 5, 7), (4, 6, 6), (4, 6, 7), (4, 7, 7), (5, 5, 5), (5, 5, 6), (5, 5, 7), (5, 6, 6)] |
[1, 2, 3] | 3 | i=1 | 2 | 2 | 3 | [2, 3] | [3, 3] | [(4, 4, 4), (4, 4, 5), (4, 4, 6), (4, 4, 7), (4, 5, 5), (4, 5, 6), (4, 5, 7), (4, 6, 6), (4, 6, 7), (4, 7, 7), (5, 5, 5), (5, 5, 6), (5, 5, 7), (5, 6, 6), (5, 6, 7)] |
[1, 3, 3] | 3 | i=0 | 3 | 1 | 3 | [1, 3, 3] | [2, 2, 2] | [(4, 4, 4), (4, 4, 5), (4, 4, 6), (4, 4, 7), (4, 5, 5), (4, 5, 6), (4, 5, 7), (4, 6, 6), (4, 6, 7), (4, 7, 7), (5, 5, 5), (5, 5, 6), (5, 5, 7), (5, 6, 6), (5, 6, 7), (5, 7, 7)] |
[2, 2, 2] | 3 | i=2 | 1 | 2 | 3 | [2] | [3] | [(4, 4, 4), (4, 4, 5), (4, 4, 6), (4, 4, 7), (4, 5, 5), (4, 5, 6), (4, 5, 7), (4, 6, 6), (4, 6, 7), (4, 7, 7), (5, 5, 5), (5, 5, 6), (5, 5, 7), (5, 6, 6), (5, 6, 7), (5, 7, 7), (6, 6, 6)] |
[2, 2, 3] | 3 | i=1 | 2 | 2 | 3 | [2, 3] | [3, 3] | [(4, 4, 4), (4, 4, 5), (4, 4, 6), (4, 4, 7), (4, 5, 5), (4, 5, 6), (4, 5, 7), (4, 6, 6), (4, 6, 7), (4, 7, 7), (5, 5, 5), (5, 5, 6), (5, 5, 7), (5, 6, 6), (5, 6, 7), (5, 7, 7), (6, 6, 6), (6, 6, 7)] |
[2, 3, 3] | 3 | i=0 | 3 | 2 | 3 | [2, 3, 3] | [3, 3, 3] | [(4, 4, 4), (4, 4, 5), (4, 4, 6), (4, 4, 7), (4, 5, 5), (4, 5, 6), (4, 5, 7), (4, 6, 6), (4, 6, 7), (4, 7, 7), (5, 5, 5), (5, 5, 6), (5, 5, 7), (5, 6, 6), (5, 6, 7), (5, 7, 7), (6, 6, 6), (6, 6, 7), (6, 7, 7)] |
댓글 없음:
댓글 쓰기