부분 집합, 조합, 탐욕 알고리즘
2024. 2. 29. 01:55ㆍ알고리즘
- 부분 집합
집합에 포함된 원소들을 선택하는 것
아무것도 선택하지 않은 경우 (공집합)도 부분 집합에 포함된다.
부분 집합 구현 방법 : 완전 탐색 / binary counting
- binary counting 을 이용한 부분 집합 탐색 코드
arr = ['A', 'B', 'C', 'D', 'E']
n = len(arr)
def get_count(tar):
count = 0
for i in range(n):
# 1비트 1인지 확인
if tar & 0x1:
count += 1
# right shift 비트 연산자를 사용하여 오른쪽 끝 비트를 하나씩 제거
tar >>= 1
return count
result = 0
for tar in range(1 << n):
if get_count(tar) >= 2: # bit 가 2개 이상 = 2명 이상
result += 1
print(result)
- 조합
서로 다른 n개의 원소 중 r개를 순서 없이 골라낸 것
5명 중 3명을 뽑으면 3중 for문이 필요
만약 5명 중 n명을 뽑으면 n중 for문이 필요해서 재귀 호출을 사용한다!
- 주사위 N개를 던져서 나오는 숫자 조합을 구하는 코드
N = 3
path = []
def func(lev, start):
if lev == N:
print(path)
return
for i in range(start, 7):
path.append(i)
func(lev + 1, i)
path.pop()
func(0, 1)
- 탐욕 알고리즘
greedy → 결정이 필요할 때, 현재 기준으로 가장 좋아 보이는 선택지로 결정하여 답을 도출한다.
대표적인 문제해결기법들
→
완전 탐색 : 답이 될 수 있는 모든 경우를 시도해보는 알고리즘
Greedy : 결정이 필요할 때 가장 좋아보이는 선택지로 결정하는 알고리즘
DP : 현재에서 가장 좋아 보이는 것을 선택하는 것이 아니라, 과거의 데이터를 이용하여, 현재의 데이터를 만들어내는 문제해결기법
분할정복 : 큰 문제를 작은 문제로 나누어 해결하는 문제해결기법
- 그리디 알고리즘 문제
arr = [15, 30, 50, 10]
arr.sort()
count = 0
for i in range(len(arr)):
count += arr[i] * (len(arr) - i - 1)
print(count)
person = [15, 30, 50, 10]
n = len(person)
person.sort()
sum = 0
left_person = n - 1 # 화장실 이용 못한 대기자 수
for turn in range(n):
time = person[turn]
# 누적합 = 남은 사람 * 시간
sum += left_person * time
left_person -= 1
print(sum)
- 도둑 문제
n = 3
target = 30
things = [(5, 50), (10, 60), (20, 140)] # (kg, price)
# kg 당 가격으로 내림차순 정렬
things.sort(key = lambda x : (x[1] / x[0]), reverse= True)
sum = 0
for kg, price in things:
per_price = price / kg
if target < kg:
sum += target * per_price
break
sum += price
target -= kg
print(int(sum))
- 회의실 문제
가장 빨리 시작하는 회의들 중 가장 빨리 끝나는 회의를 선택
가능한 회의 추리기
(반복)
- 조합 짜는 법
arr = 'ABCD'
N = len(arr)
R = 3
# 4C3
# 첫 번째 요소를 선택
pick = [0] * R # 조합 요소로 선택한 값을 저장하기 위해 미리 준비한 공간
def comb(k, start):
if k == R:
print(*pick)
return
for i in range(start, N):
# 두 번째 요소를 선택
pick[k] = arr[i] # 선택한 값을 덮어씌운다.
comb(k + 1, i + 1)
comb(0, 0)
파이썬에서는 리스트가 쓰기 편해서 append, pop을 사용해서 선택하고 재귀호출을 하지만,
다른 언어에서는 그렇게 쓰기보다는 위 코드의 pick 같은 공간을 미리 만들어놓고
선택한 값을 준비한 공간에 덮어쓰는 방식을 많이 쓴다.
'알고리즘' 카테고리의 다른 글
백트래킹 & 트리 (0) | 2024.03.20 |
---|---|
분할 정복, 정렬 (0) | 2024.03.20 |
반복과 재귀, 순열, 완전 탐색 (1) | 2024.02.27 |
비트연산과 진수 (0) | 2024.02.23 |
알고리즘 응용 준비 (0) | 2024.02.22 |