https://www.algospot.com/judge/problem/read/TSP2
algospot.com :: TSP2
Traveling Salesman Problem 2 문제 정보 문제 NP-Complete 문제의 가장 유명한 예 중 하나인 여행하는 외판원 문제 (Traveling Salesman Problem) 은, 여러 개의 도시와 그 도시 간의 거리가 주어졌을 때, 각 도시를
www.algospot.com
코드설명
동적계획법(Dynamic Programming, DP) + 비트마스킹(BitMask) + 완전탐색(BruteForce) 을 활용합니다.
TSP1 과는 다르게, N은 15입니다. 그렇기에 시간복잡도는 O(N!)임에 따라, 15! 인데, 이는 엄청나게 큰 숫자입니다.
그러므로, 메모이제이션을 활용합니다.
이떄 메모이제이션에, (현재 위치) (지금까지 방문한 위치)의 데이터를 통해 메모이제이션 합니다.
평소에 과거의 데이터를 가지고 있는 (이 문제의 경우 과거의 데이터란 지금까지 방문한 위치를 의미합니다.) 이 문제가 최적 부분 구조가 성립하는것인가? 라는 의문이 있었습니다.
항상, 이전의 데이터를 가지고 있을때에는 최적 부분구조가 성립하기 어렵다라는 생각을 했었는데, 가지고 있는 데이터들을 최소한으로 하여서 최적 부분 구조를 사용할 수 있습니다.
이 문제에서 최적 부분 구조가 성립시키려면 아래와 같이 함수를 정의합니다.
shortestPath2(int here, int visited) : here 위치에서 visited 위치들을 모두 방문한 상태일떄의 최소비용을 반환한다.
코드
package Main; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.Arrays; import java.util.StringTokenizer; public class Main { private static int C, N, W, H; private static int[][] arr; private static int answer = 0; private static double[][] dist; private static double[][] cache; public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); StringTokenizer st = new StringTokenizer(br.readLine()); C = Integer.parseInt(st.nextToken()); while(C-- > 0){ st = new StringTokenizer(br.readLine()); N = Integer.parseInt(st.nextToken()); dist = new double[N][N]; cache = new double[N][1<<N]; for(int i=0;i<N;i++) { st = new StringTokenizer(br.readLine()); for(int j=0;j<N; j++) { dist[i][j] = Double.parseDouble(st.nextToken()); } } double answer = Double.MAX_VALUE; //cache는 모든 출발지에서 사용해도 같이 공유가 가능합니다. for (double[] row : cache) { Arrays.fill(row, -1); } for(int i=0;i<N;i++) { answer = Math.min(answer, shortestPath2(i, 1<<i)); } System.out.println(String.format("%.10f", answer)); } } private static double shortestPath2(int here, int visited) { if(visited == (1 << (N)) - 1) { return 0; } if(cache[here][visited] >= 0) return cache[here][visited]; double ret = Double.MAX_VALUE; for(int next = 0; next < N; next++) { if( (visited & (1 << next)) != 0) { continue; } double cand = dist[here][next] + shortestPath2(next, visited + (1<<next)); ret =Math.min(ret, cand); } return cache[here][visited] = ret; } }