출처
- https://algospot.com/judge/problem/read/TSP1
- 프로그래밍 대회에서 배우는 알고리즘 문제해결 전략 (구종만)
난이도
- (하) – 중 – 상 – 최상 – 풀지 못함
문제
- Input으로 최대 8개 도시간의 거리가 주어진다. Salesman이 모든 도시를 한 번씩 다 방문하는데 가장 짧은 거리를 계산하는 문제이다.
후기
- 문제를 읽고 Priority Queue로 문제를 풀려고 먼저 생각해보았다. 하지만, 도시의 개수가 8개 정도로 제한이 되어 있어서 단순히 모든 가능한 방법을 다 만들어 보는 완전 탐색 방법을 사용하였다. 추가로 가지치기 (Pruning)이라는 기법에 대해서 읽었던 기억이 나서 같이 적용하면 문제를 한번 풀어보았다.
- 완전 탐색 방법과 가지치기를 사용하여 문제를 정말 쉽게 풀었다. 한번 실수를 했던 부분은 Float로 연산을 수행하니 소수점 7자리에서 오차가 조금씩 발생하여 Double로 연산을 하도록 변경하였다.
코드
- 완전 탐색 + 가지치기 방법을 사용한 코드
- Github 주소: https://github.com/mkblog-cokr/algorithmCode
- 실행 시간: 8ms (제일 빠른 코드 대비 8배(1ms) 느림)
//MK: 완전 탐색 + 가지치기 방법을 사용한 코드 #include <stdio.h> //MK: Visual Studio를 사용시 scanf 에러 제거함. #pragma warning(disable:4996) #define MAXSIZE 9 #define MIN(a,b) (a)<(b)?(a):(b) double distance[MAXSIZE][MAXSIZE]; int inputSize; double tmpAnswer; int visited[MAXSIZE]; //MK: 모든 도시를 방문했는지를 판단하는 함수 int allVisited() { for (int i = 0; i <= inputSize; i++) { if (visited[i] == 0) { return 0; } } return 1; } //MK: 모든 가능한 방법을 다 찾기 위한 완전탐색 코드 void findAnswer(int ptr, double dist) { if (allVisited() == 1) { tmpAnswer = MIN(tmpAnswer, dist); //printf("%f\n", dist); } //MK: 기존의 답 보다 긴 경우 가지치기를 하여서 더 이상 탐색을 수행하지 않음 if (dist > tmpAnswer) { return; } for (int i = 1; i <= inputSize; i++) { if (i == ptr) { continue; } if (visited[i] == 0) { visited[i] = 1; findAnswer(i, dist + distance[ptr][i]); visited[i] = 0; } } } int main(void) { int testCase; freopen("input.txt", "r", stdin); setbuf(stdout, NULL); scanf("%d", &testCase); for (int m = 1; m <= testCase; m++) { for (int i = 0; i < MAXSIZE; i++) { visited[i] = 0; } tmpAnswer = 0; scanf("%d", &inputSize); for (int i = 0; i <= inputSize; i++) { distance[i][0] = 0; distance[0][i] = 0; } for (int i = 1; i <= inputSize; i++) { for (int j = 1; j <= inputSize; j++) { scanf("%lf", &distance[i][j]); if ((i + 1) == j) { tmpAnswer += distance[i][j]; } } } visited[0] = 1; findAnswer(0, 0); printf("%.10lf\n", tmpAnswer); } return 0; }