일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- docker
- BFS
- 백준
- next-stock
- piplining
- langgraph
- 구현
- spring event
- 아키텍쳐 개선
- 검색어 추천
- ipo 매매자동화
- ai agent
- 누적합
- 쿠키
- 디버깅
- 몽고 인덱스
- 프로그래머스
- 결제서비스
- 크롤링
- gRPC
- 카카오
- 레디스 동시성
- JPA
- 트랜잭샨
- AWS
- 추천 검색 기능
- 완전탐색
- 이분탐색
- 셀러리
- jwt 표준
- Today
- Total
코딩관계론
[카카오 프로그래머스] 주사위 고르기 본문
문제 이해하기
N개의 주사위가 주어지고, 해당 주사위에는 6개의 면에 랜덤한 숫자들이 적혀있음
이 N개의 주사위 중 N/2를 A가 가져가고, 나머지를 B가 가져가고 이렇게 가져간 주사위 중 승률이 가장 높은 주사위를 반환해야함
문제 해결 방법
1. 주사위 선택을 어떻게 하냐에 따라서 결과 값이 달라지기 완전탐색을 진행해야 합니다. 파이썬에서는 combinations 함수를 통해서 주사위 조합을 구할 수 있습니다.
combi = list(combinations(range(0, len(dice)), n))
2. 내가 선택한 주사위에서 나올 수 있는 면들의 조합, 상대 방이 선택한 주사위에서 나올 수 있는 면들의 조합을 구해야 합니다.
for my_dice in combi:
enemy_dice = list(set(range(len(dice))) - set(my_dice))
my_score = []
enemy_score = []
for dice_cand in product(range(6), repeat=n):
my_score.append(sum(dice[i][j] for i, j in zip(my_dice, dice_cand)))
enemy_score.append(sum(dice[i][j] for i, j in zip(enemy_dice, dice_cand)))
3. 그 후 내가 나온 점수와 상대방이 나온 점수를 모두 비교해서 몇 번 이겼는지 계산하면 됩니다.
for my_dice in combi:
enemy_dice = list(set(range(len(dice))) - set(my_dice))
my_score = []
enemy_score = []
for dice_cand in product(range(6), repeat=n):
my_score.append(sum(dice[i][j] for i, j in zip(my_dice, dice_cand)))
enemy_score.append(sum(dice[i][j] for i, j in zip(enemy_dice, dice_cand)))
여기서 중요한 점은 이기는 횟수를 계산하기 위해서는 최대 15,243,697,152(10C5 * 6**10)이 필요하게 됩니다.
** 내가 가져갈 수 있는 주사위의 최대 수가 5가 되고, 해당 5개의 조합 6**5과 6**5을 계산하는 경우의 수는 15,243,697,152(10C5 * 6**10)이 됩니다.
따라서 승리를 빠르게 판별하기 위해서 다른 방법이 필요하게 되는데 먼저 상대방의 점수 조합을 정렬한 후 내가 만든 숫자에서 이분탐색을 수행하는 것입니다.
이렇게 계산하면 연산횟수가 1,157,606로 줄어들게 됩니다.
** 6*5을 정렬하면 연산횟수는 61,362가 되고 여기에 252(10C5)를 곱해주면 됩니다.
따라서 아래와 같이 이분탐색을 진행하고 찾아진 인덱스가 이길 수 있는 최대 개수가 됩니다.
코드
from bisect import bisect_left
from itertools import combinations, product
def solution(dice):
ans = []
ans_score = -1
n = int(len(dice) / 2)
combi = list(combinations(range(0, len(dice)), n))
for my_dice in combi:
enemy_dice = list(set(range(len(dice))) - set(my_dice))
my_score = []
enemy_score = []
for dice_cand in product(range(6), repeat=n):
my_score.append(sum(dice[i][j] for i, j in zip(my_dice, dice_cand)))
enemy_score.append(sum(dice[i][j] for i, j in zip(enemy_dice, dice_cand)))
enemy_score.sort()
can_win = sum(bisect_left(enemy_score, my) for my in my_score)
if ans_score < can_win:
ans = [dice + 1 for dice in my_dice]
ans_score = can_win
return ans
if __name__ == "__main__":
dice = [[1, 2, 3, 4, 5, 6], [3, 3, 3, 3, 4, 4], [1, 3, 3, 4, 4, 4], [1, 1, 4, 4, 5, 5]]
print(solution(dice))
배운점 정리하기
주어진 배열에서 특정 값을 찾는 것은 이분탐색을 활용하면 빠르게 해결할 수 있다는 점을 다시 한번 상기할 수 있었다.
'개발 > 알고리즘' 카테고리의 다른 글
[프로그래머스] H-index (1) | 2024.04.11 |
---|---|
[프로그래머스] 등대 (0) | 2024.04.09 |
[카카오 프로그래머스] 도넛과 막대 (0) | 2024.04.04 |
[프로그래머스] 석유 시추 (0) | 2024.04.03 |
[프로그래머스] 숫자 블록 (0) | 2023.05.21 |