2024-10-20-LGECT-3
문제
1 ~ n번으로 분류되는 n가지 서류를 발급받기 위해 관공서에 방문하려고 한다. 1 ~ m번까지 m개의 관공서가 있고, 각 관공서에서 발급한 서류 종류가 정해져 있다. 관공서에 방문하면 개수 제한 없이 원하는 서류를 발급받을 수 있다.
집과 관공서들 사이를 연결하는 길을 나타내는 무방향 그래프가 주어진다. 그래프는 m + 1개의 노드로 이루어져 있으며, 0번은 당신의 집을 나타내고 1 ~ m번 노드는 순서대로 1 ~ m + 1번 관공서를 나타낸다. 노드 사이를 연결하는 간선은 길을 나타낸다. 모든 길은 양방향으로 통과 가능하고 길을 지나는데 필요한 이동 거리는 1이다.
집에서 출발하여 모든 서류를 발급받고 집으로 돌아오는데 필요한 최소 이동거리는?

| 관공서 번호 | 서류 번호 |
|---|---|
| 1 | 1, 2, 3 |
| 2 | 3, 5 |
| 3 | 1 |
| 4 | 3, 4 |
| 5 | 2, 4 |
0 -> 2 -> 4 -> 1 -> 4 -> 0 순으로 이동하면 모든 서류 발급 가능
2번에서 3, 5 발급
4번에서 4 발급
1번에서 1, 2 발급
- 발급받아야 할 서류 개수
n - 관공서에서 발급 가능한 서류 정보를 담은 2차원 정수 배열
docs - 관공서 사이를 연결하는 길을 담은 2차원 정수 배열 roads
| roads | m |
|---|---|
| [[0, 2], [0, 3], [0, 4], [1, 4], [2, 3], [2, 4], [3, 5], [4, 5]] | 5 |
| [[0, 1], [1, 2], [2, 3], [3, 4], [1, 7], [2, 5], [5, 6], [4, 7], [0, 5]] | 7 |
제한사항
- 3 <=
n<= 8 - 3 <=
docs의 길이=m<= 100docs[i]의 길이ndocs[i][j]는 0 또는 1- 1은
i + 1번 관공서에서j + 1번 서류 발급 가능함 - 0은
i + 1번 관공서에서j + 1번 서류 발급 불가능함
- 1은
m<=roads의 길이<= 300roads의 원소는 [a, b] 형태로 a번 노드와 b번 노드를 연결하는 간선이 존재함을 의미
- 0 <=
a<=b<=mroads의 원소는 중복 X. 0번 노드에서 출발해 모든 노드 방문 가능한 경우만 주어짐
입출력 예
| docs | n |
|---|---|
| [[1, 1, 1, 0, 0], [0, 0, 1, 0, 1], [1, 0, 0, 0, 0], [0, 0, 1, 1, 0], [0, 1, 0, 1, 0]] | 5 |
| [[0, 0, 1, 0], [0, 1, 0, 1], [0, 0, 0, 0], [1, 0, 0, 1], [0, 0, 0, 1], [0, 1, 1, 1], [0, 0, 0, 0]] | 4 |
Source
from collections import deque
# n: 서류의 개수, m: 관공서의 수
def min_distance_to_collect_docs(n, m, docs, roads):
# 그래프 구성
graph = [[] for _ in range(m + 1)]
for a, b in roads:
graph[a].append(b)
graph[b].append(a)
# 관공서에서 발급 가능한 서류 정보를 비트마스크로 변환
office_docs = [0] * (m + 1) # 집(0번 노드) 포함
for i in range(m):
for j, can_issue in enumerate(docs[i]):
if can_issue:
office_docs[i + 1] |= (1 << j)
# BFS 초기화
queue = deque([(0, 0, 0)]) # (현재 노드, 발급 상태, 이동 거리)
visited = set()
visited.add((0, 0)) # (노드, 상태)
all_docs_mask = (1 << n) - 1 # 모든 서류를 발급받은 상태
while queue:
node, state, distance = queue.popleft()
# 모든 서류를 발급받은 경우
if state == all_docs_mask and node == 0:
return distance
# 현재 노드에서 발급 가능한 서류 추가
new_state = state | office_docs[node]
# 인접 노드 탐색
for neighbor in graph[node]:
if (neighbor, new_state) not in visited:
visited.add((neighbor, new_state))
queue.append((neighbor, new_state, distance + 1))
# 테스트 케이스
print(min_distance_to_collect_docs(
5, 5,
[[1, 1, 1, 0, 0], [0, 0, 1, 0, 1], [1, 0, 0, 0, 0], [0, 0, 1, 1, 0], [0, 1, 0, 1, 0]],
[[0, 2], [0, 3], [0, 4], [1, 4], [2, 3], [2, 4], [3, 5], [4, 5]]
)) # 출력: 5
print(min_distance_to_collect_docs(
4, 7,
[[0, 0, 1, 0], [0, 1, 0, 1], [0, 0, 0, 0], [1, 0, 0, 1], [0, 0, 0, 1], [0, 1, 1, 1], [0, 0, 0, 0]],
[[0, 1], [1, 2], [2, 3], [3, 4], [1, 7], [2, 5], [5, 6], [4, 7], [0, 5]]
)) # 출력: 7