본문 바로가기

코딩테스트

백준 10971: 외판원 순회 2 [JAVA]

https://www.acmicpc.net/problem/10971

 

[난이도]

- Silver 2

 

[알고리즘]

- 백트래킹

 

[코드]

import java.io.*;
import java.util.*;

public class Main {
    static int N, answer = Integer.MAX_VALUE;
    static int[][] map;
    static boolean[] visited;
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        StringTokenizer st;

        N = Integer.parseInt(br.readLine());
        map = new int[N][N];
        visited = new boolean[N];
        for (int i = 0; i < N; i++) {
            st = new StringTokenizer(br.readLine(), " ");
            for (int j = 0; j < N; j++) {
                map[i][j] = Integer.parseInt(st.nextToken());
            }
        }

        for (int i = 0; i < N; i++) {
            visited[i] = true;
            backTracking(i, i, 0, 0);
        }
        System.out.println(answer);
    }

    /**
     * @param start : 메서드 실행 전 위에서 정해줌
     * @param now : 현재 내가 위치한 도시
     * @param sum : 현재위치한 도시까지 사용한 비용
     * @param depth
     */
    static void backTracking(int start, int now, int sum, int depth) {
        if (depth == N - 1) { // 모든 도시를 모두 방문한 경우, N-1인 이유는 백트래킹 메서드를 실행하기 전에 이미 방문함
            if (map[now][start] != 0) { // 마지막 도시에서 처음 도시로 가는 비용 더하기
                sum += map[now][start];
                answer = Math.min(answer, sum); // 최종적으로 나온 비용
            }
            return;
        }
        for (int i = 0; i < N; i++) {
            if (!visited[i]) { // 방문하지 않은 도시일경우
                if (map[now][i] != 0) { // 갈수 있는 도시일경우
                    visited[i] = true; // 방문했다면 true
                    backTracking(start, i, sum + map[now][i], depth + 1);
                    visited[i] = false; // 방문이 끝나면 false
                }
            }
        }
    }
}

[풀이]

 

시작하는 도시가 1번도시로 고정이 아닌 어느도시에서 시작하든 최소비용을 찾는것이기 때문에 N번 반복한다.

        for (int i = 0; i < N; i++) {
            visited[i] = true;
            backTracking(i, i, 0, 0);
        }

 

 

백트래킹 메서드의 매개변수 start 는 순회를 시작한 도시의 위치로 메서드를 실행할 때 정해진다.

매개변수 now는 현재 내가 위치한 도시의 위치를 뜻한다. 

매개변수 sum은 현재 내가 now에 올때까지 사용한 비용을 뜻한다.

매개변수 depth는 모든도시를 순회했는지 체크한다.

 

 

for문을 돌며 방문하지 않은 도시이며 map[i][j]가 0이 아닌도시(방문할 수 있는 도시) 라면 백트래킹을 재귀적으로 수행한다.

이때 넣어주어야 하는 매개변수들은 순회를 시작한 도시 start, 다음 방문할 도시 i, 현재까지 사용한 비용(sum) + 현재 위치에서 i까지 가는 비용(map[now][i]), depth + 1이다.

        for (int i = 0; i < N; i++) {
            if (!visited[i]) { // 방문하지 않은 도시일경우
                if (map[now][i] != 0) { // 갈수 있는 도시일경우
                    visited[i] = true; // 방문했다면 true
                    backTracking(start, i, sum + map[now][i], depth + 1);
                    visited[i] = false; // 방문이 끝나면 false
                }
            }
        }

 

 

depth 가 N-1이 되면 모든도시를 방문한 것이다. depth가 N이아닌 N-1인 이유는 순회를 시작한 도시는 메서드 실행전 체크하기 때문이다.

depth가 N-1이 되었다면 마지막 도착한 도시에서 순회를 시작한 도시로 돌아와야하기 때문에 map[now][start] != 0 이라면

sum += map[now][start]를 해주어 마지막 비용을 추가해준다.

        if (depth == N - 1) { // 모든 도시를 모두 방문한 경우, N-1인 이유는 백트래킹 메서드를 실행하기 전에 이미 방문함
            if (map[now][start] != 0) { // 마지막 도시에서 처음 도시로 가는 비용 더하기
                sum += map[now][start];
                answer = Math.min(answer, sum); // 최종적으로 나온 비용
            }
            return;
        }