728x90
1035번: 조각 움직이기
최대 5개의 조각이 있는 5×5 크기의 보드가 있다. 김지민은 조각을 적절히 움직여서 모든 조각이 연결 요소를 이루게 하려고 한다. 즉 상하좌우로 인접한 조각을 모두 연결했을 때, 모든 쌍의 조
www.acmicpc.net
📄 문제개요
- 5x5 크기의 보드가 주어졌을때, 모든 조각을 움직여서 연결 요소를 만드려고 한다.
- 조각을 최소로 움직여서 연결요소를 만들 수 있는 값을 구하시오.
🤔 문제분석
- 문제의 범위가 5x5이니, 완전탐색으로 문제를 접근해야한다.
- 우선은 연결요소가 될 수 있는 모든 경우의 수를 구한다.
- 연결요소를 순열로 현재 peice와 거리 계산을 하여 최소값을 갱신한다.
📝 의사코드
- 별의 개수로 만들 수 있는 모든 조합의 경우의 수를 구한다.
- 해당 조합이 연결요소인지 판별하여 조합을 줄인다.
- 그룹핑의 개수를 계산하는 너비 우선탐색을 계산한다.
- 해당 조합을 다시 순열로 만들어서 현재 놓여진 peice값과 최소값을 갱신하며 계산한다.
💻 코드
import sys
from itertools import combinations
from itertools import permutations
from collections import deque
moves = [(0, 1), (0, -1), (1, 0), (-1, 0)]
input = sys.stdin.readline
graph = list(input().strip() for _ in range(5))
empty = []
peice = []
for i in range(5):
for j in range(5):
empty.append((i, j))
if graph[i][j] == '*':
peice.append((i, j))
def check(i, j):
return 5 > i >= 0 and 5 > j >=0
def bfs(i, j, group):
queue = deque()
queue.append((i, j))
new_graph = [['.' for _ in range(5)] for _ in range(5)]
for g_y, g_x in group:
new_graph[g_y][g_x] = '*'
new_group = []
new_group.append((i, j))
visited = [[False for _ in range(5)] for _ in range(5)]
visited[i][j] = True
while queue:
y, x = queue.popleft()
for dy, dx in moves:
ny, nx = dy + y, dx + x
if check(ny, nx) and not visited[ny][nx] and new_graph[ny][nx] == '*':
visited[ny][nx] = True
queue.append((ny, nx))
new_group.append((ny, nx))
return len(new_group) == len(group)
def isGroup(i, j, group):
return bfs(i, j, group)
groups = list(combinations(empty, len(peice)))
groups = [new_g for new_g in groups if isGroup(new_g[0][0], new_g[0][1], new_g)]
def checkdif(source, target):
return abs(source[0] - target[0]) + abs(source[1] - target[1])
ans = 10000
peice.sort()
for group in groups:
for p_group in list(permutations(group, len(peice))):
cost = 0
for i in range(len(peice)):
cost += checkdif(peice[i], p_group[i])
ans = min(cost, ans)
print(ans)
🎯 피드백 및 개선사항
- 해당문제는 5x5 배열이 주어졌으므로, 모든 경우의 수를 다 탐색해보아야하는 완전탐색으로 문제를 접근해야한다.
- 완전탐색으로 접근하지 않았을때, 문제의 접근이 조금 어려워진다.
❓다른사람은 어떻게 풀었을까?
- 나와 비슷하게 문제를 해결하신 분이 있다. 2차원 배열을 1차원 형태로 나타내어 풀어내셨다.
from itertools import combinations,permutations
from collections import deque
dR=[0,0,-1,1]
dC=[1,-1,0,0]
INF=9876543210
def calDist(A,B):
return abs(A[0]-B[0])+abs(A[1]-B[1])
def isConnect(nowL):
visited=[[0 for j in range(5)] for i in range(5)]
tempL=[[0 for j in range(5)] for i in range(5)]
for r,c in nowL:
tempL[r][c]=1
visited[nowL[0][0]][nowL[0][1]]=1
cntCon=1
q=deque([[nowL[0][0],nowL[0][1]]])
while(q):
r,c=q.popleft()
for k in range(4):
tempR=r+dR[k]
tempC=c+dC[k]
if 0<=tempR<5 and 0<=tempC<5 and visited[tempR][tempC]==0 and tempL[tempR][tempC]==1:
visited[tempR][tempC]=1
q.append([tempR,tempC])
cntCon+=1
if cntCon==size:
return True
else:
return False
L=[]
for i in range(5):
L.append(list(input()))
loc=[]
for i in range(5):
for j in range(5):
if L[i][j]=="*":
loc.append([i,j])
size=len(loc)
comb=list(combinations([i for i in range(25)],size))
ans=INF
for numL in comb:
# 번호->행렬
nowLoc=[]
for i in numL:
r=i//5
c=i%5
nowLoc.append([r,c])
# 연결여부확인
if not isConnect(nowLoc):
continue
# 거리확인
nowAns=INF
per=list(permutations([i for i in range(size)],size))
for myTuple in per:
temp=0
for i in range(size):
temp+=calDist(loc[i],nowLoc[myTuple[i]])
if temp<nowAns:
nowAns=temp
if nowAns<ans:
ans=nowAns
print(ans)
- 서로 연결되어있는지 확인하는 방법을 DFS로 풀으셨다.
from itertools import combinations, permutations
def D(c):
global res
for per in permutations(c, N):
dis = 0
for idx, p in enumerate(per):
dis += abs(Z[idx][0] - p[0]) + abs(Z[idx][1] - p[1])
res = min(res, dis)
def DFS(x, y, n):
global cnt
cnt += 1
ch[n]=1
for k in range(4):
xx, yy = dx[k]+x, dy[k]+y
if (xx, yy) in com and ch[com.index((xx, yy))] == 0:
DFS(xx, yy, com.index((xx, yy)))
dx, dy = [-1, 0, 1, 0], [0, 1, 0, -1]
gra = [list(map(str, input())) for _ in range(5)]
Z = []
arr = []
for i in range(5):
for j in range(5):
if gra[i][j] == '*':
Z.append((i, j))
arr.append((i, j))
N = len(Z) #조각수
res = 2147000000
for com in combinations(arr, N):
cnt = 0
ch = [0]*(N)
DFS(com[0][0], com[0][1], 0)
if cnt != N: continue
D(com)
print(res)
728x90
'알고리즘 > 백준' 카테고리의 다른 글
[백준] 11054번 : 가장 긴 바이토닉 부분 수열 (1) | 2023.12.10 |
---|---|
[백준] 17472번 : 다리만들기 2 (1) | 2023.12.06 |
[백준] 1759번 : 암호만들기 (1) | 2023.12.04 |
[백준] 1092번 : 배 (4) | 2023.12.04 |
[백준] 1285번 : 동전 뒤집기 (2) | 2023.12.02 |