728x90
외판원 순회(TSP)
외판원 순회 문제란 모든 도시를 한 번씩 방문하고 다시 출발점으로 되돌아오는 최소 비용을 구하는 문제이다.
N(도시의 수) 값이 작으면, 순열로도 문제를 해결할 수 있지만 N 값이 매우 커지면 불가능하다. 순열의 시간복잡도가 O(N!)일 때 N의 값이 대략 11을 넘어가면 위험하기 때문이다. N 값이 매우 클 경우, DP를 이용해서 풀어야한다.
DP + 비트마스킹
dp[current][visited]: current 도시에서 남은 도시들을 모두 방문하여 출발점으로 되돌아가기 위한 최소비용
- current: current 현재 도시
- visited: 현재까지 방문한 도시들을 비트마스킹으로 표현해놓은 것
비트마스킹
모든 도시를 방문한 경우
visited == (1<<N)-1
(1<<N)-1을 통해 모든 비트를 1로 만들 수 있다.
도시를 아직 방문하지 않은 경우
visited & (1<<next) == 0
도시 방문 표시
visited | (1<<next)
로직
- dp[current][visited]를 INF로 초기화한다.
- tsp 함수 → 재귀
- 만약 모든 도시를 방문했다면 current→출발지(0)으로 가는 비용을 return한다. 이때, current→출발지가 불가능한 경우라면, INF return한다.
- 만약 dp≠INF라면(이미 계산된 경우라면) dp 값을 return한다.
- dp값을 계산한다. 연결된 도시들을 순회하며 값을 update한다. 이때, 다음 도시는 아직 방문하지 않고, 현재 도시에서 도달할 수 있는 경우여야 한다.
문제
코드
import java.io.*;
import java.util.*;
// 152ms
// dp + 비트마스킹
public class Main_2098_G1_TSP2 {
static final int MAX_NUM = 98765432;
static int N; // N: 도시의 수
static int[][] adjMatrix;
// dp[current][visited]: current에서 출발하여 visited에서 방문하지 않은 도시들을 모두 거쳐
// 다시 0(출발지)로 되돌아오기 위한 최소비용
static int[][] dp;
public static int tsp(int current, int visited){
// 더이상 방문할 도시가 없다면 return
if( visited == ((1<<N)-1) ) return adjMatrix[current][0]==0 ? MAX_NUM : adjMatrix[current][0];
// 이미 계산된 경우라면?
if( dp[current][visited]!=0 ) return dp[current][visited];
// 인접한 도시들 방문
int minVal = MAX_NUM;
for(int next=0; next<N; next++){
// current -> next가 불가능한 경우 next
if(adjMatrix[current][next]==0) continue;
// 방문했다면 next
if((visited & (1<<next)) !=0 ) continue;
minVal = Math.min(minVal, adjMatrix[current][next]+tsp(next,visited | (1<<next)));
}
return dp[current][visited] = minVal;
}
public static void main(String[] args) throws IOException{
// 1. 입력 및 초기화
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st;
N = Integer.parseInt(br.readLine());
adjMatrix = new int[N][N];
dp = new int[N][1<<N];
for(int i=0; i<N; i++){
st = new StringTokenizer(br.readLine());
for(int j=0; j<N; j++){
adjMatrix[i][j] = Integer.parseInt(st.nextToken());
}
}
System.out.println(tsp(0,1));
}
}
728x90
'알고리즘 > 백준' 카테고리의 다른 글
[알고리즘]백준 2493: 탑 (1) | 2024.07.14 |
---|---|
[알고리즘]백준 12015: 가장 긴 증가하는 부분수열(LIS) (0) | 2024.07.12 |
[알고리즘]백준 1238: 파티 (0) | 2024.06.23 |
[알고리즘]백준 10986: 나머지 합 (0) | 2024.06.19 |
B12460. 구슬탈출2 (1) | 2024.02.04 |