개발 블로그
[CodeTree/파이썬] 방화벽 설치하기 문제풀이/시간복잡도 줄이기 본문
코드트리 | 코딩테스트 준비를 위한 알고리즘 정석
국가대표가 만든 코딩 공부의 가이드북 코딩 왕초보부터 꿈의 직장 코테 합격까지, 국가대표가 엄선한 커리큘럼으로 준비해보세요.
www.codetree.ai
사고흐름
1. 방화벽 설치하는 모든 경우 탐색 -> 조합
2. 해당 방화벽 위치에 따른 불 영역 구하기 -> DFS, BFS
시간 복잡도 줄이기 과정
1. 첫번째 시도는 그냥 막 작성한거 -> 시간 초과
2. 처음에는 BFS로 불영역 구할때 for문으로 2인거 찾아서 해당 좌표에서 BFS 시작했는데, 그걸 줄이기 위해 불 영역을 저장한 리스트를 가지고 거기서 차례대로 탐색 -> 2000ms
3. 방화벽 조합 구하는 방법 수정: 원래는 DFS로 구했는데 3중 for문으로 구해봄 (이게 가능했던 것은 3가지만 고르면 되기때문) -> 465ms
4. deque 사용 뺌 -> 580ms
두번째코드
n,m = map(int, input().split())
board = [list(map(int, input().split())) for _ in range(n)]
wall_num = 0
ground = []
comb = []
moves = [(1,0),(0,1),(-1,0),(0,-1)]
fire = []
for i in range(n):
for j in range(m):
if board[i][j]==1:
wall_num+=1
elif board[i][j]==0:
ground.append((i,j))
else:
fire.append((i,j))
# 방화벽 3개 모든 조합 구하기
def combination(v):
if len(v)==3:
comb.append(v[:])
return
for g in ground:
if g not in v:
v.append(g)
combination(v)
v.pop()
# 불 번짐
def fire_area(x, y, board):
q = [(x,y)]
cnt = 1
board[x][y]=-1
while q:
v = q.pop(0)
for move in moves:
dx,dy = v[0]+move[0],v[1]+move[1]
if 0<=dx<n and 0<=dy<m and board[dx][dy]!=1 and board[dx][dy]!=-1:
board[dx][dy]=-1
cnt+=1
q.append((dx,dy))
return cnt
combination([])
ans = n*m
for com in comb:
board_copy = [b[:] for b in board]
fire_cnt = 0
for c in com:
board_copy[c[0]][c[1]]=1
for f in fire:
if board_copy[f[0]][f[1]]!=-1:
fire_cnt += fire_area(f[0], f[1], board_copy)
ans = min(ans, fire_cnt)
print(n*m-ans-wall_num-3)
세번째 코드 (최적)
from collections import deque
n,m = map(int, input().split())
board = [list(map(int, input().split())) for _ in range(n)]
wall_num = 0
ground = []
comb = []
moves = [(1,0),(0,1),(-1,0),(0,-1)]
fire = []
for i in range(n):
for j in range(m):
if board[i][j]==1:
wall_num+=1
elif board[i][j]==0:
ground.append((i,j))
else:
fire.append((i,j))
# 방화벽 3개 모든 조합 구하기
def combination():
for i in range(len(ground)-2):
for j in range(i+1, len(ground)-1):
for k in range(j+1, len(ground)):
comb.append((ground[i],ground[j],ground[k]))
# 불 번짐
def fire_area(x, y, board):
q = deque()
q.append((x,y))
cnt = 1
board[x][y]=-1
while q:
v = q.popleft()
for move in moves:
dx,dy = v[0]+move[0],v[1]+move[1]
if 0<=dx<n and 0<=dy<m and board[dx][dy]!=1 and board[dx][dy]!=-1:
board[dx][dy]=-1
cnt+=1
q.append((dx,dy))
return cnt
combination()
ans = n*m
for com in comb:
board_copy = [b[:] for b in board]
fire_cnt = 0
for c in com:
board_copy[c[0]][c[1]]=1
for f in fire:
if board_copy[f[0]][f[1]]!=-1:
fire_cnt += fire_area(f[0], f[1], board_copy)
ans = min(ans, fire_cnt)
print(n*m-ans-wall_num-3)
시간 줄이기 팁
1. 조합이나 순열 구할때 DFS나 BFS도 좋지만, comb(n, list) 중 n이 4이하라면 차라리 다중 for문으로 구현하는게 훨 빠를수있다!!
2. deque 사용
'Algorithm' 카테고리의 다른 글
[백준/파이썬] G3_15683 감시 문제풀이/시간 복잡도 줄이기 (2) | 2024.10.03 |
---|---|
[Codetree/파이썬] 돌아가는 팔각 의자 문제풀이 (0) | 2024.09.23 |
[Programmers/파이썬] 프로그래머스(Lv.2) 우박수열 정적분 문제풀이 (0) | 2024.08.23 |
[Programmers/파이썬] 프로그래머스(Lv.1) 삼총사 문제풀이 (0) | 2024.08.22 |
[Programmers/파이썬] 프로그래머스(Lv.2) 택배상자 문제풀이 (0) | 2024.08.22 |