[백준] 2098번 외판원 순회 (C++)
문제
외판원 순회 문제는 영어로 Traveling Salesman problem (TSP) 라고 불리는 문제로 computer science 분야에서 가장 중요하게 취급되는 문제 중 하나이다.
도시가 N개 있고, 각 도시들 사이에는 길이 있을 수도, 없을 수도 있다. 이제 한 외판원이 한 도시에서 출발해 N개의 도시를 모두 거쳐 다시 원래의 도시로 돌아오는 순회 여행 경로를 계획하려고 한다.
단, 한 번 갔던 도시로는 다시 갈 수 없다. (맨 마지막에 여행을 출발했던 도시로 돌아오는 것은 예외)
이런 여행 경로 중에서 가장 적은 비용을 들이는 여행 계획을 세우고자 한다.
입력
첫째 줄에 도시의 수 N이 주어진다. (2 ≤ N ≤ 16)
다음 N개의 줄에는 비용 행렬이 주어진다.
각 행렬의 성분은 1,000,000 이하의 양의 정수이며, 갈 수 없는 경우는 0이 주어진다.
W[i][j]는 도시 i에서 j로 가기 위한 비용을 나타낸다.
항상 W[i][i] = 0이다.
예제 입력 1
4
0 10 15 20
5 0 9 10
6 13 0 12
8 8 9 0
출력
첫째 줄에 외판원의 순회에 필요한 최소 비용을 출력한다.
예제 출력 1
35
풀이
문제 해결 방법
이 문제는 TSP(Traveling Salesman Problem)의 대표적인 예시로, 다이나믹 프로그래밍과 비트마스킹을 함께 사용하여 해결할 수 있습니다. 주요 해결 단계는 다음과 같습니다:
- 상태 표현: 현재 방문한 도시들의 집합과 현재 위치를 상태로 표현
- 비트마스킹: 방문한 도시들의 집합을 비트마스크로 표현
- DP 테이블: dp[방문한 도시들의 상태][현재 위치]
- 최적해 계산: 모든 도시를 방문한 후 출발 도시로 돌아오는 최소 비용 계산
이 알고리즘의 시간 복잡도는 O(N² × 2^N)입니다.
코드
#include<stdio.h>
#include<algorithm>
using namespace std;
int dp[66000][17];
int n;
int mp[17][17];
int main()
{
int i, j, k;
scanf("%d", &n);
for (i = 1; i <= n; i++)
for (j = 1; j <= n; j++)
scanf("%d", &mp[i][j]);
for (i = 0; i <= (1 << n); i++)
{
for (j = 1; j <= n; j++)
dp[i][j] = 1e9;
}
dp[1][1] = 0;
for (i = 2; i < (1 << n); i++)
{
for (j = 1; j <= n; j++)
{
if (i &(1 << (j - 1)))
{
int v = i - (1 << (j - 1));
for (k = 1; k <= n; k++)
{
if (mp[k][j] == 0)continue;
dp[i][j] = min(dp[i][j], dp[v][k] + mp[k][j]);
}
}
}
}
int mn = 1e9;
int v = (1 << n) - 1;
for (i = 2; i <= n; i++)
{
if (mp[i][1] == 0)continue;
mn = min(mn, dp[v][i] + mp[i][1]);
}
printf("%d", mn);
return 0;
}
댓글남기기