본문 바로가기
코딩캠프/BOJ

[2098] 외판원 순회

by 코곰_ 2024. 2. 23.
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

int N, start, W[16][16], dp[16][65536];//1<<16 = 2^16개의 노드의 방문 여부를 비트로 표시.
const int IMPOSSIBLE = 1000000000;

/*
현재 외판원이 current번 마을에 있고, 방문한 마을 집합이 visited일 때
앞으로 남은 모든 마을을 방문하고 0번 마을로 돌아갈 때 드는 최소 비용
*/
int TSP(int current, int visited){
    /*
    기저 사례: 모든 마을을 방문한 경우,
    현재 마을에서 시작지점으로 갈 수 있으면 해당 비용을 리턴하고
    아닐 경우 불가능 값을 리턴한다.
    */
    if(visited == (1<<N)-1){// 모두 방문
        if(W[current][start]==0){
            //시작점으로 돌아갈 수 없다면
            return IMPOSSIBLE;
        }else{
            return W[current][start];
        }
    }

    int &ret = dp[current][visited];
    if(ret != -1){
        //-1이 아니라면 자명한 최소값(dpCost[][]) 바로 리턴.
        return ret; 
    } 

    ret = IMPOSSIBLE;
    // 아직 방문하지 않은 모든 도시들을 순회해 봄
    for(int i=0; i<N; i++){
        if(visited & (1<<i)) continue; // 방문한적이 있다면 **
        if(W[current][i]==0) continue; // 다음 도시로 갈수가 없다면 ** 
        //현재 노드에서 재귀적으로 다음 노드 방문.
        ret = min(ret, TSP(i, visited | (1<<i)) + W[current][i]);
    }
    return ret;
}

int main(){
    scanf("%d", &N);
    for(int i=0; i<N; i++)
        for(int j=0; j<N; j++)
            scanf("%d", &W[i][j]);
    memset(dp, -1, sizeof(dp));
    //0 : 0번 노드가 첫 시작노드 / 1 : 1은 2^0 -> 즉 시작 노드인 0번 노드를 방문했음을 표시)
    //어떤 도시에서 출발하던 비용은 같으므로 0번 노드를 첫 시작노드로 임의 설정.
    printf("%d\n", TSP(0, 1));

}

'코딩캠프 > BOJ' 카테고리의 다른 글

[5719] 거의 최단경로  (0) 2024.02.23
[5582] 공통 부분 문자열  (0) 2024.02.23
[9252] LCS2  (0) 2024.02.23
[11660] 구간 합 구하기 5  (1) 2024.02.22
[14002] 가장 긴 증가하는 부분수열4  (0) 2024.02.22