[파이썬] 백준 1035 : 조각 움직이기 (골드1)
1035번: 조각 움직이기
최대 5개의 조각이 있는 5×5 크기의 보드가 있다. 김지민은 조각을 적절히 움직여서 모든 조각이 연결 요소를 이루게 하려고 한다. 즉 상하좌우로 인접한 조각을 모두 연결했을 때, 모든 쌍의 조
www.acmicpc.net
문제
풀이
0. 방향성 생각
- array 상태가 * . 두개만 존재 + 5*5 : 2^25 -> bitmask
- 조각이 상태를 int로 변환해준 후, bitmask로 연산을 줄여준다.
- list로 변환하지 않고 bitstream을 이용해주면 더 빨리 풀 수 있지만, TLE안나고 충분히 가능할거라 생각해서 현재 상태를 2차원 array로 바꿔서 연결요소 개수를 체크한다.
1. 입력
from collections import deque
start,p,count = 0,0,0
for _ in range(5):
for s in input():
if s == '*':
start += 2**p
count += 1
p += 1
dire = [(1,0),(0,1),(-1,0),(0,-1)]
- power는 0부터 시작하나 24부터 시작하나 상관x. 어짜피 대칭형이라 상관없다.
- 현재 시작 array 형태를 int로 바꿔서 start에 넣는다.
2. list변환, BFS, update 함수 정의
def to_5x5(integer):
string = bin(integer)[2:].rjust(25,'0')
arr = [list(string[5*i:5*i+5]) for i in range(5)]
return arr
def bfs(x,y):
cnt = 1
visited = [[False]*5 for _ in range(5)]
visited[y][x] = True
q = deque([(x,y)])
while q:
x,y = q.popleft()
for dx,dy in dire:
nx,ny = x+dx, y+dy
if 0<=nx<5 and 0<=ny<5 and not visited[ny][nx] and x_list[ny][nx] == '1':
q.append((nx,ny))
visited[ny][nx] = True
cnt += 1
return cnt
def update(nxt):
global visit,q
if nx not in visit:
visit.add(nx)
q.append((nx,t+1))
- 현재 상태를 2차원 array로 바꿔주는 to_5x5
- 2차원 array에서 1을 만났을 때, 연결요소의 개수를 반환하는 BFS
- 비트연산을 해준 결과를 업데이트 할지 말지 결정해주는 update
3. 출력
if count == 1:
print(0)
else:
visit = set()
visit.add(start)
q = deque([(start,0)])
while q:
x,t = q.popleft()
x_list = to_5x5(x)
connect = False
for i in range(5):
for j in range(5):
if x_list[i][j] == '1' and bfs(j,i) == count:
connect = True
break
if connect:
print(t)
break
for i in range(25):
if (x>>i)&1:
if i<20 and not x&(1<<(i+5)):
nx = x^(1<<i)
nx = nx^(1<<(i+5))
update(nx)
if i>4 and not x&(1<<(i-5)):
nx = x^(1<<i)
nx = nx^(1<<(i-5))
update(nx)
if i%5 != 0 and not x&(1<<(i-1)):
nx = x^(1<<i)
nx = nx^(1<<(i-1))
update(nx)
if i%5 != 4 and not x&(1<<(i+1)):
nx = x^(1<<i)
nx = nx^(1<<(i+1))
update(nx)
- visit에 현재 상태를 출력한다. list로 하면 배열 크기가 320만이라 딕셔너리로 저장
- 현재 상태 x를 x_list로 바꿔서 BFS시킨다.
- BFS 반환값으로 연결유무를 파악한다.
- 연결되지 않았으면 bit연산을 통해 업데이트
- 2차원 array 형태로 생각하면 된다. (x>>i)&1로 조각 유무를 판단한다.
- 맨 윗줄은 위로 이동 못하므로 i <20 조건을 걸어준다. 또한 이동하려는 자리에 조각이 없어야한다.
- 상하우좌 순서대로 움직이는 if문을 줘서 업데이트 했다.
전체코드
from collections import deque
start,p,count = 0,0,0
for _ in range(5):
for s in input():
if s == '*':
start += 2**p
count += 1
p += 1
dire = [(1,0),(0,1),(-1,0),(0,-1)]
def to_5x5(integer):
string = bin(integer)[2:].rjust(25,'0')
arr = [list(string[5*i:5*i+5]) for i in range(5)]
return arr
def bfs(x,y):
cnt = 1
visited = [[False]*5 for _ in range(5)]
visited[y][x] = True
q = deque([(x,y)])
while q:
x,y = q.popleft()
for dx,dy in dire:
nx,ny = x+dx, y+dy
if 0<=nx<5 and 0<=ny<5 and not visited[ny][nx] and x_list[ny][nx] == '1':
q.append((nx,ny))
visited[ny][nx] = True
cnt += 1
return cnt
def update(nxt):
global visit,q
if nx not in visit:
visit.add(nx)
q.append((nx,t+1))
if count == 1:
print(0)
else:
visit = set()
visit.add(start)
q = deque([(start,0)])
while q:
x,t = q.popleft()
x_list = to_5x5(x)
connect = False
for i in range(5):
for j in range(5):
if x_list[i][j] == '1' and bfs(j,i) == count:
connect = True
break
if connect:
print(t)
break
for i in range(25):
if (x>>i)&1:
if i<20 and not x&(1<<(i+5)):
nx = x^(1<<i)
nx = nx^(1<<(i+5))
update(nx)
if i>4 and not x&(1<<(i-5)):
nx = x^(1<<i)
nx = nx^(1<<(i-5))
update(nx)
if i%5 != 0 and not x&(1<<(i-1)):
nx = x^(1<<i)
nx = nx^(1<<(i-1))
update(nx)
if i%5 != 4 and not x&(1<<(i+1)):
nx = x^(1<<i)
nx = nx^(1<<(i+1))
update(nx)
코멘트
비트마스킹도 풀다보니까 많이 빨라진듯
풀고보니까 마지막 주변 조각 이동하는 논리랑 똑같이 개수세는 BFS 시켜도 됐네...
'Algorithm > etc' 카테고리의 다른 글
[파이썬] 백준 2632 : 피자판매 : (골드2) (0) | 2024.02.25 |
---|---|
[파이썬] 1484 : 다이어트 (골드5) (0) | 2024.01.16 |
[파이썬] 백준 3089 : 네잎 클로버를 찾아서 (골드2) (0) | 2023.12.18 |
[파이썬] 백준 22945 : 팀 빌딩 (골드4) (0) | 2023.12.12 |
[파이썬] 프로그래머스 : 모음사전 (Lv.2) (0) | 2023.11.30 |
[파이썬] 프로그래머스 : 타겟 넘버 (Lv.2) (0) | 2023.11.10 |
[파이썬] 백준 1405 : 미친로봇 (골드4) (0) | 2023.11.05 |
댓글