[알고리즘] 피자 배달 거리(삼성 SW역량평가 기출문제 : DFS활용)
(문제) 피자 배달 거리(삼성 SW역량평가 기출문제 : DFS활용)
N×N 크기의 도시지도가 있습니다. 도시지도는 1×1크기의 격자칸으로 이루어져 있습니다.
각 격자칸에는 0은 빈칸, 1은 집, 2는 피자집으로 표현됩니다.
각 격자칸은 좌표(행번호, 열 번호)로 표현됩니다.
행번호는 1번부터 N번까지이고, 열 번호도 1부터 N까지입니다.
도시에는 각 집마다 “피자배달거리”가 았는데 각 집의 피자배달거리는 해당 집과 도시의 존재하는 피자집들과의 거리 중 최소값을 해당 집의 “피자배달거리”라고 한다.
집과 피자집의 피자배달거리는 | x1-x2 | + | y1-y2 | 이다. |
예를 들어, 도시의 지도가 아래와 같다면
(1, 2)에 있는 집과 (2, 3)에 있는 피자집과의 피자 배달 거리는 | 1-2 | + | 2-3 | = 2가 된다. |
최근 도시가 불경기에 접어들어 우후죽순 생겼던 피자집들이 파산하고 있습니다.
도시 시장은 도시에 있는 피자집 중 M개만 살리고 나머지는 보조금을 주고 폐업시키려고 합니다.
시장은 살리고자 하는 피자집 M개를 선택하는 기준으로 도시의 피자배달거리가 최소가 되는 M개의 피자집을 선택하려고 합니다.
도시의 피자 배달 거리는 각 집들의 피자 배달 거리를 합한 것을 말합니다.
입력설명
첫째 줄에 N(2 ≤ N ≤ 50)과 M(1 ≤ M ≤ 12)이 주어진다.
둘째 줄부터 도시 정보가 입력된다.
출력설명
첫째 줄에 M개의 피자집이 선택되었을 때 도시의 최소 피자배달거리를 출력한다.
테스트케이스
입력예제 | 출력예제 |
---|---|
4 4 0 1 2 0 1 0 2 1 0 2 1 2 2 0 1 2 |
6 |
5 3 0 2 0 1 2 1 2 1 0 0 0 0 0 2 0 2 0 2 0 1 1 0 0 2 0 |
7 |
10 7 0 2 0 0 0 0 0 0 1 1 2 0 0 0 1 0 1 0 0 0 0 2 0 0 0 0 2 0 1 0 0 0 0 1 1 0 0 0 0 0 2 0 0 0 2 0 0 2 0 0 0 1 0 2 0 2 0 0 0 0 2 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 |
22 |
해결방법
m개의 피자집이 만들어 질 수 있는 좌표를 모두 구하면서 도시와의 거리를 측정하면 최소의 값을 찾아낸다.
- 도시와 피자집의 좌표를 각각 저장할 수 있는 리스트를 생성하여 지도상에서 전체 순회를 통해 각각의 리스트에 도시, 피자집 좌표를 append 한다.
- dfs를 통해 피자집 좌표를 저장하는 리스트에서 m 개 만큼만 남을 수 있도록 모든 경우를 알아 본다.
- 만약 dfs를 통해 m 개의 피자집 좌표가 저장 되어있는 리스트를 찾으면 도시의 리스트에 있는 모든 도시 좌표들과 m 개 저장 되어있는 피자집 좌표 리스트의 좌표들과 각각 거리를 측정하여 그 거리를 각 도시를 나타내는 딕셔네리로 만들어 전부 저장한다.
(저장을 안하고, 따로 가장 작은 것만 저장하는 변수안에 넣을 수 있기는 하지만 확인을 위해 딕셔네리에 넣었다.) - 모든 도시들 기준으로 저장을 했을 경우 그 딕셔너리 안에 있는 거리들 중 가장 짧은 것들 끼리 더해서 min 이라는 변수와 비교하여 min 보다 작을 경우 해당 min을 그 거리로 바꾼다.
- 이 과정을 모든 m개의 피자집을 만들 수 있는 경우에 수에 반복하여 적용하고, 끝날 때 min이라는 것을 출력한다.
코드
import copy
# L 피자집의 개수만 큼만 깊이 들어가기
def dfs(L):
global _min
# 피자들 개수 까지
if L == len(pizzas):
# 만약 m 개의 피자집만 존재할 경우
if len(copy_pizzas) - copy_pizzas.count(0) == m:
# 도시와 피자와의 거리를 전부 더한다
# 도시와 피자집을 기억하기 위한 딕셔너리를 생성
a = dict()
# 각 도시들 중에서 가장 작은 거리 끼리 더하기 위한 변수
total = 0
# 도시에서 피자집까지 가는 모든 경우의 길이를 딕셔너리에 저장
for i in range(len(citys)):
for j in range(len(pizzas)):
# 0이 아닐 경우에만 저장
if copy_pizzas[j] != 0:
if a.get(i):
a[i].append(abs(citys[i][0] - copy_pizzas[j][0]) + abs(citys[i][1] - copy_pizzas[j][1]))
else:
a[i] = [abs(citys[i][0] - copy_pizzas[j][0]) + abs(citys[i][1] - copy_pizzas[j][1])]
# 저장한 길이의 짧은 것들만 더한다
for x in a.values():
total = total + min(x)
if total < _min:
_min = total
return
else:
copy_pizzas[L] = pizzas[L]
dfs(L + 1)
copy_pizzas[L] = 0
dfs(L + 1)
n, m = map(int, input().split())
maps = [list(map(int, input().split())) for _ in range(n)]
citys = []
pizzas = []
for i in range(n):
for j in range(n):
# 1(도시) 의 위치를 찾는다
if maps[i][j] == 1:
citys.append((i, j))
# 2(피자집) 의 위치를 찾는다
elif maps[i][j] == 2:
pizzas.append((i, j))
_min = 2147000000
copy_pizzas = [0] * len(pizzas)
dfs(0)
print(_min)
댓글남기기