본문 바로가기
알고리즘

[Swift 알고리즘] 백준 10871 (외판원 순회2)

by 마라민초닭발로제 2023. 4. 7.

 

 

문제

외판원 순회 문제는 영어로 Traveling Salesman problem (TSP) 라고 불리는 문제로 computer science 분야에서 가장 중요하게 취급되는 문제 중 하나이다. 여러 가지 변종 문제가 있으나, 여기서는 가장 일반적인 형태의 문제를 살펴보자.

1번부터 N번까지 번호가 매겨져 있는 도시들이 있고, 도시들 사이에는 길이 있다. (길이 없을 수도 있다) 이제 한 외판원이 어느 한 도시에서 출발해 N개의 도시를 모두 거쳐 다시 원래의 도시로 돌아오는 순회 여행 경로를 계획하려고 한다. 단, 한 번 갔던 도시로는 다시 갈 수 없다. (맨 마지막에 여행을 출발했던 도시로 돌아오는 것은 예외) 이런 여행 경로는 여러 가지가 있을 수 있는데, 가장 적은 비용을 들이는 여행 계획을 세우고자 한다.

각 도시간에 이동하는데 드는 비용은 행렬 W[i][j]형태로 주어진다. W[i][j]는 도시 i에서 도시 j로 가기 위한 비용을 나타낸다. 비용은 대칭적이지 않다. 즉, W[i][j] 는 W[j][i]와 다를 수 있다. 모든 도시간의 비용은 양의 정수이다. W[i][i]는 항상 0이다. 경우에 따라서 도시 i에서 도시 j로 갈 수 없는 경우도 있으며 이럴 경우 W[i][j]=0이라고 하자.

N과 비용 행렬이 주어졌을 때, 가장 적은 비용을 들이는 외판원의 순회 여행 경로를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 도시의 수 N이 주어진다. (2 ≤ N ≤ 10) 다음 N개의 줄에는 비용 행렬이 주어진다. 각 행렬의 성분은 1,000,000 이하의 양의 정수이며, 갈 수 없는 경우는 0이 주어진다. W[i][j]는 도시 i에서 j로 가기 위한 비용을 나타낸다.

항상 순회할 수 있는 경우만 입력으로 주어진다.

출력

첫째 줄에 외판원의 순회에 필요한 최소 비용을 출력한다.

 

 

풀이 방법

https://zeddios.tistory.com/176

 

TSP는 NP-Complete.

안녕하세요 :) 주말 잘 보내시고 계신가요 ㅎㅎ?비도 오고 그래서 뭔가 코딩하기 싫은...날이라서 계속 쓰자고 쓰자고 마음먹었던 NP-Hardness의 3탄!!!!바로 TSP(Traveling Salesman Problem)는 NP-Complete라는

zeddios.tistory.com

아마 외판원 문제라면 이 tistory를 확인하면 좋을 것 같다. 어떻게 해결할까에 대해서 계속 고민했다.

 

https://sapjilkingios.tistory.com/entry/SwiftDFS-%EB%B0%B1%EC%A4%80-10971%EB%B2%88-%EC%9B%90%ED%8C%90%EC%9B%90-%EC%88%9C%ED%9A%8C-2

 

[Swift][DFS] 백준 10971번 (외판원 순회 2)

요구능력 : DFS에 대한 이해 코드설명 : 문제의 입력에는 4 0 10 15 20 5 0 9 10 6 13 0 12 8 8 9 0 가 적혀있다. 나처럼 이해못하는 사람을 위해서 해석해보자면, 도시가 4개 있는데, 1번도시는 1번에서 1번가

sapjilkingios.tistory.com

구현은 이 tistory를 확인했다. 너무 어려웠다...

 


func sol10971() {
    let N = Int(readLine()!)!
    var nodeArr:[[Int]] = []
    for i in 0..<N {
        let tempInput = readLine()!.split(separator: " ").map{Int($0)!}
        nodeArr.append(tempInput)
    }
    
    
    var minSum = Int.max //합 초기화
    var visited = Array(repeating: false, count: N) //visited라는 bool형 Array를 통해 접근한다.
    func dfs(_ currentInd: Int, _ depth:Int, _ currentSum: Int) { //세가지 인자를 받는다.현재 Ind, depth, 현재 합계
        //세가지 인자를 통해 값을 계산한다.
        if depth == N && currentInd == 0{
            minSum = min(minSum, currentSum)
            return
        }
        for i in 0 ..< N {
            if nodeArr[currentInd][i] > 0 && !visited[i] {
                // 만약 nodearr[이전][현재]가 0보다 작지 않고 -> 작다면 갈 수 없다(ex. nodeArr[0][0] = 0)
                // 접근했던 자료형이 아니라면
                visited[i] = true // 현재 값을 false로 바꾼다.
                let tempSum = currentSum + nodeArr[currentInd][i] //현재 임시 합계에 값을 더한다.
                if tempSum < minSum { //만약 임시 합계가 현재 minSum보다 크다면? 비교할 가치가 없다.
                    dfs(i, depth + 1, tempSum)
                }
                visited[i] = false
            }
        }
        
    }
    dfs(0, 0, 0)
    print(minSum)
}