알고리즘/그래프
[BOJ] 백준 10971 - 외판원 순회 2
송승현(SSH)
2023. 4. 2. 12:26
1. 문제
https://www.acmicpc.net/problem/10971
10971번: 외판원 순회 2
첫째 줄에 도시의 수 N이 주어진다. (2 ≤ N ≤ 10) 다음 N개의 줄에는 비용 행렬이 주어진다. 각 행렬의 성분은 1,000,000 이하의 양의 정수이며, 갈 수 없는 경우는 0이 주어진다. W[i][j]는 도시 i에서 j
www.acmicpc.net
2. 풀이
- 외판원(TSP)의 기본 문제 중 하나이다.
- 노드의 개수 <= 12면 BackTracking으로 해결 가능하나, 노드의 개수가 13 이상 16이하면 DP로 문제를 해결해야 한다.
- 이 문제의 경우 노드가 10개 이므로 BackTracking으로 해결이 가능하다.
- 시간 복잡도 -> $O(x^n)$
주요 자료구조
1. int[][] inMatrix : 인접 행렬
2. boolean[] nodeVisited : 노드 방문 처리 배열
- 입력으로 주어지는 값으로 인접 행렬을 구성한다.
- 이 문제의 포인트는 최소 값을 가지는 경로는 하나이기 때문에 모든 정점에서 DFS를 돌 필요 없이, 하나의 정점에서만 DFS를 돌면 최소 비용 경로가 보장된다.
- TspBackTracking() 함수를 돌면서 방문하지 않았고, 인접한 노드를 방문처리 하며 DFS를 돈다.
- 이때 재귀를 돌 때 isLoop()를 실행하여 모든 정점을 돌았는지 판단하고, 음의 가중치가 없기 때문에 마지막 노드에서 첫 번째 노드로 가는 길이 있을 때, 최소가 보장된다.
- 따라서 이때까지 더한 가중치의 최솟값을 result 변수에 갱신한다.
3. 소스 코드
import java.io.*;
import java.util.StringTokenizer;
/*
* 노드의 개수 <= 12면 백트래킹 가능
* 13 <= 노드의 개수 <= 16이면 DP로 해야함
* 시간 복잡도 O(x^n) : x = 간선의 개수, n = 노드의 개수
*/
public class Main {
static int N; // 도시 수
static int[][] inMatrix; // 인접 행렬
static boolean[] nodeVisited; // 노드 방문처리 배열
static long result = Long.MAX_VALUE;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
N = Integer.parseInt(br.readLine());
// 인접행렬 구성
inMatrix = new int[N][N];
for (int i = 0; i < N; i++) {
StringTokenizer st = new StringTokenizer(br.readLine());
for (int j = 0; j < N; j++) {
inMatrix[i][j] = Integer.parseInt(st.nextToken());
}
}
// 어차피 최소 경로는 하나일 것이기 때문에 모든 정점에서 할 필요 없이 한 점에서만 하면 된다.
nodeVisited = new boolean[N];
nodeVisited[0] = true;
TspBackTracking(0, 0, 0);
bw.write(Long.toString(result));
bw.flush();
bw.close();
br.close();
}
// 외판원 함수
private static void TspBackTracking(int start, int idx, long val) {
// 만약 모든 정점을 돌았고 마지막 정점에서 첫번째 정점까지 가는 길이 있을 때
if (isLoop() && inMatrix[idx][start] != 0) {
result = Long.min(result, val + inMatrix[idx][start]);
return;
}
for (int i = 1; i < N; i++) {
if (!nodeVisited[i] && inMatrix[idx][i] != 0) {
nodeVisited[i] = true;
TspBackTracking(start, i, val + inMatrix[idx][i]);
nodeVisited[i] = false;
}
}
}
// 모든 정점을 돌았는지 확인하는 함수
private static boolean isLoop() {
for (int i = 0; i < N; i++) {
if (!nodeVisited[i]) {
return false;
}
}
return true;
}
}
4. 점수
80 / 100