집합 {1, 2, 3}의 원소에 대해 각 부분집합에서의 포함 여부를 트리로 표현
def f(i, k, key):
if i == k: # 내가 k에 접근하려고 하면 (배열 모든 원소에 접근하려고 하면), 하나의 부분집합 완성
s = 0
for j in range(k):
if bit[j]:
if bit[j]:
s += A[j] # 부분집합의 합
if s == key:
return 1
return 0
# if s == key: # 합이 key 와 같은 부분집합
# for j in range(k):
# if [bit]j:
# print(A[j], end = ' ')
# print()
else:
bit[i] = 1 # A[i] 에서 할일
if f(i + 1, k, key):
return 1
bit[i] = 0
if f(i + 1, k, key): # 갈림길이 2개면 2번의 재귀호출
return 1
return 0
1 넣고 아래 자리로 단계로 가서 1, 1 / 1, 0 이런 방식으로 작동
단순히 합만 필요로하는 경우에는 비트를 만들 필요가 없다
위 매단계마다 비트 배열을 읽어서 합을 더하는 것은 가치지기 안하는 것
부분집합 합을 보면 찾고자 하는 합보다 크면 남은 집합 고려할 필요 없다, 가지치기
def f(i, k, s, t): # i원소, k집합의 크기, s i-1까지 고려된 합
global = cnt
global = fcmt
fcmt += 1
if s > t: # 고려한 원소의 합이 찾는 합보다 큰 경우 (함수 호출 수가 줄게된다) (이게 없으면 모든 경우 다 뒤짐)
return
elif s == t: # 내가 찾는 목표에 도달했을 때 (남은원소 있거나 없거나)
cnt += 1
return # 나머지 고려할 필요 없어
elif i == k: # 너 마지막 원소인데?, 모든원소 고려
return
# if s == t:
# for j in range(k):
# if [bit]j:
# print(A[j], end=" ")
# print()
# cnt += 1
return
else:
bit[i] = 1 # bit i를 1로 만들었다
f(i + 1, k, s+A[i], t) # A[i] 포함, 이전까지 포함된 합 s에 내가 포함하기로 한 애를 더해서 넘겨줄게
bit[i] = 0
f(i + 1, k, s, t) # A[i] 미포함
A = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
N = len(A)
key = 10
cnt = 10
bit = [0] * N
fcnt = 0
f(0, N, 0, key)
print(cnt, fcnt) # 합이 key인 부분집합의 수
그냥 부분집합의 합만 계산
1 -> 3(+2) / 1(+0)
0 -> 2(+2) / 0(+0)
남은 구간의 합을 어떻게 매번 구하지?
앞 고려한 구간을 전체에서 뺀다 (전체 - 고려한 구간 - 뒷 원소부터 차례로 빼간다(-4, -3, ...))
f(i, N)
if i == N #순열 완성
else
# 가능한 모든 원소에 대해 P[i] 결정
f(i + 1, N)
P[i] 복구 (원본으로 만들어 놓고 다시 옆에 꺼랑 바꿈)
def f(i, k):
if i == k:
print(p)
else:
for j in range(i, k):
p[i], p[j] = p[j], p[i] # 자리를 교환해봐
f(i + 1, k)
p[i], p[j] = p[j], p[i] # 원상복귀 해주는 부분이 없으면 중복이 생김
p = [1, 2, 3]
N = len(p)
f(0, N)
주어진 배열을 두 개로 분할하고, 각각을 정렬
- 다른점: 합병 정렬은 그냥 두 부분으로 나누는 반면에, 퀵정렬은 분할할 때 기준아이템 중심으로 작은 것은 왼편, 큰 것은 오른편에 위치시킨다
- 다른점2: 각 부분 정렬이 끝난 후, 합병정렬은 "합병"이란 후처리 작업이 필요하나, 퀵정렬은 필요로 하지 않는다