[파이썬] 프로그래머스 : 표 병합 (레벨3)
풀이
방향성 생각
- 입력이 (50*50) * 1000 = 25만
- 각 command마다 루프를 전부 돌아도 시간이 부족하지 않은 문제.
- 각 노드들을 연결했다, 끊었다 -> 유니온 파인드?
- 그냥 구현으로도 풀 수 있겠지만, 유니온 파인드로 진행.
- 2차원 리스트에서 반복적으로 다른 리스트로 이동하게 되면 시간적으로 부담돼서 1차원으로 변경.
- MERGE, UNMERGE 이후 2500개의 셀을 훑고 업데이트 해야 하므로 1차원으로 바꿈.
전체코드
def solution(commands):
parent = [i for i in range(51*51)]
cells = ['EMPTY']*(51*51)
# 경로 압축을 해줘야 시간이 오래 걸리지 않는다.
def find(a):
if parent[a] != a:
parent[a] = find(parent[a])
return parent[a]
# a의 부모쪽으로 유니온 파인드를 진행한다.
def union(a,b):
pa,pb = find(a),find(b)
parent[pb] = pa
# 경로가 끊기는 문제가 발생해서 MERGE,UNMERGE 후에 업데이트 시킨다.
def update():
for i in range(51*51):
find(i)
answer = []
for command in commands:
cmd = command.split()
# 1. 업데이트를 하는 경우
if cmd[0] == 'UPDATE':
# 특정 위치에 값을 넣는 경우
if len(cmd) == 4:
_,r,c,v = cmd
x = 51*int(r)+int(c)
cells[parent[x]] = v
# v1값을 v2로 변경하는 경우
else:
_,v1,v2 = cmd
for i in range(51*51):
if cells[parent[i]] == v1:
cells[parent[i]] = v2
# 2. 셀 합치는 경우
elif cmd[0] == 'MERGE':
r1,c1,r2,c2 = map(int,cmd[1:])
x1,x2 = 51*r1+c1,51*r2+c2 # 현재 셀
p1,p2 = find(x1),find(x2) # 부모 셀
# 셀이 다르면 유니온 파인드 진행
if p1 != p2:
# 각 셀이 빈 셀인지, 값이 있는 셀인지 확인한다.
v1,v2 = 'EMPTY','EMPTY'
for i in range(51*51):
if i == p1 and cells[i] != 'EMPTY': v1 = cells[i]
if i == p2 and cells[i] != 'EMPTY': v2 = cells[i]
# v2에만 값이 있으면 p2를 루트노드로
if v1 == 'EMPTY' and v2 != 'EMPTY':
x,v,p = x2,v2,p2
union(p2,p1)
# v1에만 값이 있으면 p1을 루트노드로
else:
x,v,p = x1,v1,p1
union(p1,p2)
# 현재 선택한 셀에서 루트 노드만 값을 넣어주고 나머지는 EMPTY
for i in range(51*51):
if parent[i] == p: # 현재 그룹
if i != p: cells[i] == 'EMPTY'
else: cells[i] = v
update()
# 3. 셀 병합 풀기
elif cmd[0] == 'UNMERGE':
r,c = map(int,cmd[1:])
p = parent[51*r+c] # 선택한 셀의 부모
v = cells[p] # 셀의 값
for i in range(51*51):
# 현재 지정한 그룹일 경우 병합 해제
if parent[i] == p:
parent[i] = i # 병합 해제
# 지정한 위치에는 값을 넣고 아닌 곳은 EMPTY
if i != 51*r+c: cells[i] = 'EMPTY'
else: cells[i] = v
update()
else:
r,c = map(int,cmd[1:])
answer.append(cells[parent[51*r+c]])
return answer
코멘트
- 루트 노드만 제대로 업데이트 해주면 어렵지 않은 문제
- MST 문제를 많이 풀면서 유니온 파인드에는 크게 문제가 없었는데 어떤 노드를 루트로 지정하는지, 유니온 과정에서 루트 노드 지정이 풀렸을 때 어떻게 처리하는 문제는 없었는데 이번에 다시 공부했음.
- 루트 노드를 끊어놓는 테케를 넣으려고 일부러 입력을 50*50 사이즈로 준 듯 하다.
- 첨언을 하자면, 기존 문제에서는 union(a,b)로 어떤 노드든 그냥 합쳐놓고 그루핑만 하는 문제였다.
- 이 문제에서는 유니온을 하더라도 셀 값을 가지는 루트노드가 따로 있기 때문에 어떤 노드를 루트 노드로 지정하는지가 중요하다.
- 일반적인 문제에서는 작은쪽을 루트노드로 지정해서 parent[max(a,b)] = min(a,b) 이런 방식으로 풀이를 했다.
- 저런 식으로 풀지 않으면, 모든 노드에 대해서 find를 진행해서 루트 노드를 업데이트 해야한다.
'Algorithm > Graph' 카테고리의 다른 글
[파이썬] 백준 10282 : 해킹 (골드4) (0) | 2024.02.28 |
---|---|
[파이썬] 백준 2610 : 회의준비 (골드2) (0) | 2024.02.28 |
[파이썬] 프로그래머스 : 수레 움직이기 (레벨3) (0) | 2024.02.28 |
[파이썬] 백준 16954 : 움직이는 미로탈출 (골드3) (0) | 2024.02.19 |
[파이썬] 백준 9347 : 울타리 (골드3) (0) | 2024.02.18 |
[파이썬] 백준 14466 : 소가 길을 건너간 이유 6 (골드 4) (0) | 2024.01.29 |
[파이썬] 백준 1162 : 도로포장 (플레5) (0) | 2023.12.25 |
댓글