[파이썬] 프로그래머스 : 광물캐기 (Lv.2)
프로그래머스
코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.
programmers.co.kr
풀이
방향성 생각
한 곡괭이를 고르면 5개는 무조건 파야한다.
minerals를 5개씩 묶어서 하나의 구간으로 생각한다.
BFS를 돌리면서 곡괭이 수와 stage, stamina를 조절한다.
1. stage 묶기
from collections import deque
def solution(picks, minerals):
arr,answer = [],[] # 5개씩 묶기
p,q = divmod(len(minerals),5)
for i in range(p):
table = {'diamond':0,'iron':0,'stone':0}
for mineral in minerals[i*5:i*5+5]:
table[mineral] += 1
arr.append(tuple(table.values()))
if q:
table = {'diamond':0,'iron':0,'stone':0}
for mineral in minerals[p*5:p*5+q]:
table[mineral] += 1
arr.append(tuple(table.values()))
5개씩 묶어야 하므로 최소 p번 돌리고 5로 나누어 떨어지지 않는 경우 나머지 q가 발생한다. 이 때 따로 추가해준다.
2-1. BFS
d,i,s = picks
q = deque([(d,i,s,0,0)]) #(다이아,철,돌,스테이지,스테미너)
while q:
d,i,s,stage,stamina = q.popleft()
if (d+i+s) == 0 or stage == len(arr) : # 남은 곡괭이 0 or 끝까지 도달
answer.append(stamina)
else :
x,y,z = arr[stage]
for idx,remain in enumerate((d,i,s)):
if remain: # 현재 곡괭이 남았으면 종류에 맞춰서 계산
if idx == 0 :
q.append((d-1,i,s,stage+1,stamina+(x+y+z)))
elif idx == 1:
q.append((d,i-1,s,stage+1,stamina+(5*x+y+z)))
else :
q.append((d,i,s-1,stage+1,stamina+(25*x+5*y+z)))
return min(answer)
큐에 (다이아 곡괭이,철 곡괭이, 돌 곡괭이, 스테이지, 스태미너) 순으로 넣어준다.
곡괭이를 모두 사용했거나 ( d+i+s == 0) 마지막 스테이지를 클리어 (stage == len(arr))했으면 정답 answer에 추가해준다.
ex) 테스트 케이스의 경우 minerals의 길이가 8이므로 총 2스테이지로 이루어져있다.
stage 0, stage 1을 클리어하고 다음 큐에 들어올 때 stage 2가 된다. 즉 모두 클리어했으므로 answer에 추가해준다.
그렇지 않은 경우에는 현재 클리어해야할 스테이지에 각 광물이 몇 개씩 있는지 확인해준다. x,y,z, = arr[stage]
곡괭이가 남아있는 경우에 곡괭이의 종류에 맞춰서 큐에 추가해준다.
정답 후보군 answer 중 최소값인 min(answer)을 리턴한다.
2-2. 브루트포스
tools = [] # 우선순위 다이아 철 돌
tools.extend(['diamond']*min(picks[0],len(minerals)))
tools.extend(['iron']*min(picks[1],len(minerals)-len(tools)))
tools.extend(['stone']*min(picks[2],len(minerals)-len(tools)))
case = set(P(tools,min(len(arr),len(tools))))
for tool in case:
temp = list(zip(tool,arr))
stamina = 0
for tool,mineral in temp:
if tool == 'diamond': stamina += sum(map(lambda x,y:x*y,mineral,(1,1,1)))
elif tool == 'iron': stamina += sum(map(lambda x,y:x*y,mineral,(5,1,1)))
else: stamina += sum(map(lambda x,y:x*y,mineral,(25,5,1)))
answer.append(stamina)
return min(answer)
이 코드는 순열 생성할 때 너무 많아서 테스트케이스 24 25 33 35 시간 초과 발생
순열 생성이 아니라 다른 방법으로 하면 시간초과 안걸릴같은데 생각이 안남.
2-3. 그리디, 백트래킹
if len(arr) > sum(picks): # 곡괭이보다 스테이지 수 많으면 다 못캠
for i in range(len(arr)-sum(picks)):
arr.pop()
tools = [] # 우선순위 다이아 철 돌 순으로 곡괭이 챙김
tools.extend(['diamond']*min(picks[0],len(minerals)))
tools.extend(['iron']*min(picks[1],len(minerals)-len(tools)))
tools.extend(['stone']*min(picks[2],len(minerals)-len(tools)))
case = list(C(tools,len(arr)))
case.sort()
arr.sort(key=lambda x:(-x[0],-x[1],-x[2]))
for tool in case:
temp = list(zip(tool,arr))
stamina = 0
for tool,mineral in temp:
if tool == 'diamond': stamina += sum(map(lambda x,y:x*y,mineral,(1,1,1)))
elif tool == 'iron': stamina += sum(map(lambda x,y:x*y,mineral,(5,1,1)))
else: stamina += sum(map(lambda x,y:x*y,mineral,(25,5,1)))
answer.append(stamina)
return min(answer)
그리디로 정렬해서 풀 경우에는 곡괭이가 부족해서 캐지 못하는 부분도 정렬해서 앞으로 빠질 수 있다.
이를 제거해주고 조합을 활용해서 곡괭이 순서, 광물 캐는 순서 둘다 다이아 많은 순으로 해준다
dia iron stone 알파벳순 정렬이라 둘 다 정렬하면 된다.
전체코드
1. BFS
from collections import deque
def solution(picks, minerals):
arr,answer = [],[] # 5개씩 묶기
p,q = divmod(len(minerals),5)
for i in range(p):
table = {'diamond':0,'iron':0,'stone':0}
for mineral in minerals[i*5:i*5+5]:
table[mineral] += 1
arr.append(tuple(table.values()))
if q:
table = {'diamond':0,'iron':0,'stone':0}
for mineral in minerals[p*5:p*5+q]:
table[mineral] += 1
arr.append(tuple(table.values()))
d,i,s = picks
q = deque([(d,i,s,0,0)]) #(다이아,철,돌,스테이지,스테미너)
while q:
d,i,s,stage,stamina = q.popleft()
if (d+i+s) == 0 or stage == len(arr) : # 남은 곡괭이 0 or 끝까지 도달
answer.append(stamina)
else :
x,y,z = arr[stage]
for idx,remain in enumerate((d,i,s)):
if remain: # 현재 곡괭이 남았으면 종류에 맞춰서 계산
if idx == 0 :
q.append((d-1,i,s,stage+1,stamina+(x+y+z)))
elif idx == 1:
q.append((d,i-1,s,stage+1,stamina+(5*x+y+z)))
else :
q.append((d,i,s-1,stage+1,stamina+(25*x+5*y+z)))
return min(answer)
2. 브루트포스
from itertools import permutations as P
def solution(picks, minerals):
arr,answer = [],[] # 5개씩 묶기
p,q = divmod(len(minerals),5)
for i in range(p):
table = {'diamond':0,'iron':0,'stone':0}
for mineral in minerals[i*5:i*5+5]:
table[mineral] += 1
arr.append(tuple(table.values()))
if q:
table = {'diamond':0,'iron':0,'stone':0}
for mineral in minerals[p*5:p*5+q]:
table[mineral] += 1
arr.append(tuple(table.values()))
tools = [] # 우선순위 다이아 철 돌
tools.extend(['diamond']*min(picks[0],len(minerals)))
tools.extend(['iron']*min(picks[1],len(minerals)-len(tools)))
tools.extend(['stone']*min(picks[2],len(minerals)-len(tools)))
case = set(P(tools,min(len(arr),len(tools))))
for tool in case:
temp = list(zip(tool,arr))
stamina = 0
for tool,mineral in temp:
if tool == 'diamond': stamina += sum(map(lambda x,y:x*y,mineral,(1,1,1)))
elif tool == 'iron': stamina += sum(map(lambda x,y:x*y,mineral,(5,1,1)))
else: stamina += sum(map(lambda x,y:x*y,mineral,(25,5,1)))
answer.append(stamina)
return min(answer)
3. 그리디, 백트래킹
from itertools import combinations as C
def solution(picks, minerals):
arr,answer = [],[] # 5개씩 묶기
p,q = divmod(len(minerals),5)
for i in range(p):
table = {'diamond':0,'iron':0,'stone':0}
for mineral in minerals[i*5:i*5+5]:
table[mineral] += 1
arr.append(tuple(table.values()))
if q:
table = {'diamond':0,'iron':0,'stone':0}
for mineral in minerals[p*5:p*5+q]:
table[mineral] += 1
arr.append(tuple(table.values()))
if len(arr) > sum(picks): # 곡괭이보다 스테이지 수 많으면 다 못캠
for i in range(len(arr)-sum(picks)):
arr.pop()
tools = [] # 우선순위 다이아 철 돌 순으로 곡괭이 챙김
tools.extend(['diamond']*min(picks[0],len(minerals)))
tools.extend(['iron']*min(picks[1],len(minerals)-len(tools)))
tools.extend(['stone']*min(picks[2],len(minerals)-len(tools)))
case = list(C(tools,len(arr)))
case.sort()
arr.sort(key=lambda x:(-x[0],-x[1],-x[2]))
for tool in case:
temp = list(zip(tool,arr))
stamina = 0
for tool,mineral in temp:
if tool == 'diamond': stamina += sum(map(lambda x,y:x*y,mineral,(1,1,1)))
elif tool == 'iron': stamina += sum(map(lambda x,y:x*y,mineral,(5,1,1)))
else: stamina += sum(map(lambda x,y:x*y,mineral,(25,5,1)))
answer.append(stamina)
return min(answer)
코멘트
문제 좋은듯
'Algorithm > Graph' 카테고리의 다른 글
[파이썬] 백준 17141 : 연구소2 (골드4) (0) | 2023.07.12 |
---|---|
[파이썬] 백준 14502 : 연구소 (골드4) (0) | 2023.07.11 |
[파이썬] 프로그래머스 : 미로탈출 (Lv.2) (0) | 2023.07.07 |
[파이썬] 백준 5567 : 결혼식 (실버2) (0) | 2023.07.06 |
[파이썬] 백준 1765 : 닭싸움 팀 정하기 (골드2) (0) | 2023.07.05 |
[파이썬] 프로그래머스 : 섬 연결하기 (Lv.3) (0) | 2023.07.05 |
[파이썬] 백준 9694 : 무엇을 아느냐가 아니라 누구를 아느냐가 문제다 (골드3) (0) | 2023.07.03 |
댓글