정올 1681 : 해밀턴 순환회로
Updated:
Java
1681 : 해밀턴 순환회로
문제
배달해야 하는 장소의 수 N(1≤N≤12)이 주어진다. 이때, 출발지(회사)는 1번이다.
둘째 줄은 N X N 크기의 장소와 장소를 이동하는 비용(0 ≤ 비용< 100)이 한 칸씩의 공백으로 구분하여 주어진다.
비용은 양방향이 아니라 단방향으로 가기 위한 비용이다.
물건을 모두 배달하고 회사로 돌아오기 위한 최소의 비용을 계산하는 프로그램을 작성해 주자.
장소 사이에 이동할 수 있는 방법이 없다면 비용을 0으로 표시한다.
접근 방법
DFS과 백트래킹으로 해결하였다.
시작 노드 0에서 부터, n개 까지 반복하며, 방문하지 않았은 노드로 갈 수 있으면 그 가중치를 더하고 다음 DFS로 탐색하며 반복한다.
다음 노드로 방문할 때, 그 가중치의 합이 n개 만큼 노드를 방문하였을 때 얻은 가중치의 값보다 작을 때만 탐색하게 하여 Back Tracking을 수행하였다.
주의할 점은, 갈 수 없으면 0으로 표시 되어 있으므로 이 것을 처리해야한다.
코드
import java.util.*;
import java.io.*;
public class Main {
static int n, result = Integer.MAX_VALUE;
static int[][] graph;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer stk;
n = stoi(br.readLine());
graph = new int[n][n];
for(int i = 0; i < n; i++) {
stk = new StringTokenizer(br.readLine());
for(int j = 0; j < n; j++) {
graph[i][j] = stoi(stk.nextToken());
}
}
DFS(0, 0, new boolean[n], 0);
System.out.println(result);
br.close();
}
// 시그니처는 왼쪽에서 부터 [현재까지 뽑은 노드의 개수, 현재 노드, 방문 여부, 총 합]
private static void DFS(int lv, int curN, boolean[] vis, int sum) {
if(lv == n - 1) { // n - 1개의 노드를 다 방문 하였을 시
if(graph[curN][0] != 0) { // 마지막 노드에서 첫 번째 노드로 갈 수 있으면
sum += graph[curN][0];
result = Math.min(result, sum); // n개 만큼의 가중치의 최소 값을 갱신
}
return;
}
vis[curN] = true; // 방문한 노드는 방문 처리한다.
for(int i = 1; i < n; i++) {
// 방문하지 않은 노드이며 && 다음 노드의 합이 현재까지의 최소 값보다 작으며 && 이어져 있어 갈 수 있으면
if(!vis[i] && sum + graph[curN][i] < result && graph[curN][i] != 0) {
DFS(lv + 1, i, vis.clone(), sum + graph[curN][i]);
}
}
}
static int stoi(String str) {
return Integer.parseInt(str.replaceAll(" ", ""));
}
}
총평
난이도
⭐⭐★★★
후기
문제의 조건 중 하나인, 이동 할 수 없는 경우는 0으로 구분해주어야 하는 것을 놓쳤다.
개선할 점
없