문제를 정리해보자.
위 판매망은 판매원이 칫솔을 판매하면 그 이익이 피라미드 조직을 타고 조금씩 분배되는 형태이다.
각각은 자신을 조직에 참여시킨 추천인에게 연결되어 피라미드식의 구조를 이루고 있다.
조직의 이익 분배 규칙은 다음과 같다.
1. 이익에서 10%를 계산하여 자신을 조직에 참여시킨 추천인에게 배분하고 나머지는 자신이 가진다.
+ 모든 판매원은 자신이 칫솔 판매에서 발생한 이익뿐만 아니라, 자신이 조직에 추천하여 가입시킨 판매원에게서 발생하는 이익의 10%까지 자신에 이익이 된다.
+ 자신에게 발생하는 이익 또한 마찬가지의 규칙으로 자신의 추천인에게 분배된다
2. 단, 10%를 계산할 때는 원 단위에서 절사한다. 그리고 10%를 계산한 금액이 1원 미만인 경우에는 이득을 분배하지 않고 자신이 모두 가진다.
풀이를 생각해보자.
예를 들어, 아래와 같은 판매 기록이 있다고 가정하자.
(칫솔의 판매에서 발생하는 이익은 개당 100원으로 정해져 있다.)
그러면 아래와 같은 결과가 파악하고자 하는 이익 배분 현황이 된다.
이 현황을 구하는 방법은 2가지로 예상된다.
1. 이익이 발생할 때마다 이익을 분배한다.
2. 이익을 누적시켰다가 한번에 분배한다. (합산X)
아래는 두 번째 방법의 설계도이다.
각각 장단점
첫 번째 방법)
이 문제의 핵심은 다음과 같다.
1. '10%를 계산한 금액이 1원 미만인 경우에는 이득을 분배하지 않고 자신이 모두 가진다.'
2. 판매량 범위는 1이상 100이하의 자연수이다. (따라서 판매 최대이득은 10,000이다.)
1원 미만인 경우는 재귀가 돌 필요가 없다. 따라서 재귀가 무조건 1000번 이하로 끝난다.
하지만 노드 재방문이 많다.
두 번째 방법)
노드를 재방문하지 않는다는 장점이 있다.
하지만 파이썬은 재귀 깊이가 1,000으로 제한되어 있다.
이 문제를 보면 판매원이 최대 10,000명까지 존재한다.
따라서 직선 트리의 경우 재귀의 깊이가 10,000까지 가게 된다.
따로 제한을 풀어주지 않으면 통과할 수 없다.
구현해보자
두 번째 방법으로 구현했다.
import math
import sys
sys.setrecursionlimit(100000) # 직선 트리
# DFS
def dfs(tree, start_name, check, money):
check[start_name] = 1
for name in tree[start_name]:
if check[name] == 0:
money[start_name] += dfs(tree, name, check, money)
# 10% 계산
tmp = []
for idx, cal_money in enumerate(money[start_name]):
cal = math.trunc(cal_money * 0.1)
# 1원 미만은 추가에 제한
if cal > 0:
money[start_name][idx] -= cal
tmp.append(cal)
return tmp
def solution(enroll, referral, seller, amount):
l = len(enroll)
tree = {'-': []}
check = {'-': 0}
money = {'-': [0]}
# 트리 생성
for i in range(l):
parent = referral[i]
child = enroll[i]
check[child] = 0
money[child] = [0]
if not tree.get(child, 0):
tree[child] = []
tree[parent].append(child)
# 판매량 집계 데이터의 판매 수량 (합산 판매 X)
for idx, name in enumerate(seller):
money[name].append(amount[idx] * 100)
# DFS
dfs(tree, '-', check, money)
# 결과
answer = []
for name in enroll:
answer.append(sum(money[name]))
return answer
print(solution(["john", "mary", "edward", "sam", "emily", "jaimie", "tod", "young"], ["-", "-", "mary", "edward", "mary", "mary", "jaimie", "edward"], ["young", "john", "tod", "emily", "mary"], [12, 4, 2, 5, 10]))
시행착오
이득은 얻을 때마다 추천인과 분배하는 것이다. 얻은 이득을 합산해서 추천인과 분배하면 완전 다른 값이 나온다.
'알고리즘 > 프로그래머스' 카테고리의 다른 글
[프로그래머스][2021 KAKAO BLIND RECRUITMENT][Python] 순위 검색 (0) | 2022.03.02 |
---|---|
[프로그래머스][2021 KAKAO BLIND RECRUITMENT][Python] 신규 아이디 추천 (0) | 2022.02.22 |
[프로그래머스][2021 Dev-Matching: 웹 백앤드 개발자(상반기)][Python] 로또의 최고 순위와 최저 순위 (0) | 2022.02.21 |
[프로그래머스][2022 KAKAO BLIND RECRUITMENT][Python] 파괴되지 않은 건물 (0) | 2022.02.16 |
[프로그래머스][2022 KAKAO BLIND RECRUITMENT][Python] k진수에서 소수 개수 구하기 (2) | 2022.02.10 |