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

코드설명

백트래킹 + DFS + 외판원 순회 문제(Traveling Salesman Problem (TSP) ) 문제입니다.

 

이 문제에서 처음에는 문제이해가 어려웠습니다.

처음에 이해했을때, 1-. 2-> 3-> 4-> 3-> 2-> 1 로 이동하는 것이라고 생각하였고,

1->2->3->4 로 이동하는방법은 DFS로 찾는다고 가정하여도 4->1 로 갈때 과연 그것이 최단거리를 보장할 수 있는가? 라는 생각이 들었습니다. 그러나 생각해보면 문제에서 한번 방문했던 공간은 다시 돌아갈 수 없기에 4->1로 가는것이 맞습니다. 만약에 4->1로 돌아가지 못한다면 해당 방안은 유효하지 않는 경로입니다.

 

이 문제 같은경우 1->2->3->4->1 로 생각해야합니다.

 

사이클이 존재하는 이유는, 출발지점에서 다시 출발지점으로 돌아와야하기 떄문입니다.

문제의 사이클을 확인해보면,

2->3->4->1->2

3->4->1->2->3

...

위와 같이 결국 경로가 사이클이 존재하여 어디서든 출발하든 결국에는 같은 경로입니다.

 

그렇기에 어디서든 출발하든 값은 같습니다. 즉, 한번만 simulate()를 해주면 답을 찾을 수 있습니다.

코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;
public class Main {
public static int N;
public static int answer = Integer.MAX_VALUE;
public static boolean[] visited;
public static int[][] graph;
public static void main(String[] args) throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
graph = new int[N][N];
for(int i=0;i<N;i++) {
st = new StringTokenizer(br.readLine());
for(int j=0;j<N;j++) {
graph[i][j] = Integer.parseInt(st.nextToken());
}
}
//1 -> 2 -> 3 -> 4 -> 1
visited = new boolean[N];
visited[0] = true;
simulate(0, 0, 1, 0);
System.out.println(answer);
}
public static void simulate(int originalStart, int nowIdx, int cnt, int sum) {
//모든 경로 다 방문햇을경우 종료시킵니다.
if(cnt == N) {
if(graph[nowIdx][originalStart] != 0) {
answer = Math.min(answer, sum + graph[nowIdx][originalStart]);
}
return ;
}
for(int i=0;i<N;i++) {
if(visited[i] == false && graph[nowIdx][i] != 0) {
visited[i] = true;
simulate(originalStart, i, cnt + 1, sum + graph[nowIdx][i]);
visited[i] = false;
}
}
}
}

+ Recent posts