길민호(ethan.mino)
코딩수첩
길민호(ethan.mino)
전체 방문자
오늘
어제
  • 분류 전체보기 (215)
    • Computer Science (0)
    • Web (6)
      • CSS (0)
      • HTML (0)
    • Node.js (0)
    • Javascript (2)
    • Java (46)
      • Spring (27)
      • Jsp (0)
    • C\C++ (2)
    • Programming (0)
    • AI (0)
    • Database (7)
    • Git (5)
    • Algorithm (119)
      • Stack (0)
      • Queue (0)
      • Linked List (0)
      • Sort (0)
      • Simulation (27)
      • Recursion (0)
      • Backtracking (4)
      • Two Pointer (3)
      • Dynamic Programming (19)
      • Greedy (10)
      • Graph (3)
      • Dijkstra (1)
      • BFS\DFS (8)
      • Floyd (1)
      • MST (4)
      • Tree (4)
      • Binary Search (8)
      • Binary Search Tree (4)
    • IntelliJ (4)
    • Vscode (0)
    • Operating System (0)
    • 후기 (3)
    • 성장일지 (13)
    • 스터디 (7)
    • 설치 (1)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • ㅡ

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
길민호(ethan.mino)

코딩수첩

Algorithm/Dynamic Programming

[SW Expert Academy 1247번] 최적 경로

2022. 7. 2. 22:13

https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AV15OZ4qAPICFAYD 

 

SW Expert Academy

SW 프로그래밍 역량 강화에 도움이 되는 다양한 학습 컨텐츠를 확인하세요!

swexpertacademy.com


최적 경로 문제는 다이나믹 프로그래밍과 비트 미스킹으로 해결할 수 있습니다.

 

N이 최대 10이기 때문에, 경로의 모든 경우의 수를 계산하여 해결할 수도 있지만,

다이나믹 프로그래밍을 이용하면 시간을 단축시킬 수 있습니다.

 

TSP(Traveling Salesman Problem)


아래는 TSP 함수로,

현재 위치가 cur이고, 방문 상태가 visited일 때, 고객들을 모두 방문하고, 집으로 돌아가는 최소 비용을 반환합니다.

#define x first
#define y second
#define SIZE 12
#define INF 100000
int weight[SIZE][SIZE];
int d[SIZE][1<<SIZE];  // d[cur][visted]는 현재 cur이고, visted를 방문한 상태일 때, 고객들을 모두 방문하고, 집으로 돌아가는 최소 비용
int n;
pii st, en; // 회사, 집의 위치

int TSP(int cur, int visited){
    int &ret = d[cur][visited];
    if(ret != 0) return ret;

    if(visited == (1 << (n + 1))-1) {    // 모두 방문한 경우
        return weight[cur][n + 1];
    }

    ret = INF;
    for(int i = 0; i <= n; i++){
        if(visited&(1<<i)) continue; // 이미 방문한 경우
        // 방문하지 않은 경우
        ret = min(ret, TSP(i, (visited|1<<i)) + weight[cur][i]);
    }
    return ret;
}

 

TSP 함수 의 알고리즘은 아래와 같습니다. 

  1. 이미 결과 값이 있는 경우 반환
  2. 회사와 모든 고객을 방문한 경우, 현재 위치에서 집까지의 거리를 반환
  3. 방문하지 않은 고객 nx가 있는 경우, (cur과 nx간의 거리 + (현재 nx이고, visited와 nx를 방문한 상태일 때 집으로 돌아가는 최소 비용)) 중 가장 작은 값을 반환

비트 마스킹


visited는 현재 어느 위치를 방문했는지 나타내는 정수입니다. 

예를 들어 10011(2)인 경우, 0번, 1번, 4번 위치를 방문한 것을 나타냅니다. (회사는 0번, 집은 n + 1번 위치)

 

visited == (1 << (N + 1))-1로 회사와 모든 고객을 방문했는지 알 수 있습니다.

예를 들어 N이 5인 경우, 회사를 포함하여 6개의 위치를 방문해야합니다. (집은 마지막에 방문해야하므로 제외)

1 << (5 + 1)은 1000000(2)이고, (1 << (N + 1)) - 1은 111111(2)이 되어 회사와 모든 고객을 방문했음을 나타냅니다. 

 

또한, (visited & (1<<nx))로 nx가 이미 방문한 위치인지 확인할 수 있습니다.

예를 들어 visited가 10010(2)이고, nx가 2라면, (1 << nx)는 00100(2)이 됩니다.

10010(2)과 00100(2)을 AND 연산하면, 결과는 0이 나옵니다. 즉, false(방문하지 않음)입니다. 

  10010
& 00100
---------
  00000

예를 들어 visited가 10010(2)이고, nx가 1이라면, (1 << nx)는 00010(2)이 됩니다.

10010(2)과 00010(2)을 AND 연산하면, 결과는 2이 나옵니다. 즉, true(이미 방문함)입니다. 

  10010
& 00010
---------
  00010

 

또한, (visited | 1 << nx)로 nx를 방문 표시할 수 있습니다.

예를 들어, visited가 10010(2)이고, nx가 2일 때, (visited | 1 << nx)의 결과는 10110(2)입니다.

  10010
| 00100
---------
  10110

 

🚀 Solution 


아래는 전체 코드입니다.

// Created by 길민호 on 2022/07/02.

#include <bits/stdc++.h>
using namespace std;

typedef pair<int, int> pii;

#define x first
#define y second
#define SIZE 12
#define INF 100000
int weight[SIZE][SIZE];
int d[SIZE][1<<SIZE];  // d[cur][visted]는 현재 cur이고, visted를 방문한 상태일 때, 고객들을 모두 방문하고, 집으로 돌아가는 최소 비용
int n;
pii st, en; // 회사, 집의 위치

int TSP(int cur, int visited){
    int &ret = d[cur][visited];
    if(ret != 0) return ret;

    if(visited == (1 << (n + 1))-1) {    // 모두 방문한 경우
        return weight[cur][n + 1];
    }

    ret = INF;
    for(int i = 0; i <= n; i++){
        if(visited&(1<<i)) continue; // 이미 방문한 경우
        // 방문하지 않은 경우
        ret = min(ret, TSP(i, (visited|1<<i)) + weight[cur][i]);
    }
    return ret;
}

int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    int t; cin >> t;
    int cur = 1;
    while(t--){
        vector<pii> pos;
        fill(&d[0][0], &d[SIZE - 1][1 << SIZE], 0);

        cin >> n;
        cin >> st.x >> st.y;
        cin >> en.x >> en.y;

        pos.push_back(st);
        for(int i = 0; i < n; i++){
            pii c; cin >> c.x >> c.y;
            pos.push_back(c);
        }
        pos.push_back(en);

        for(int i = 0; i < n + 2; i++)
            for(int j = 0; j < n + 2; j++)
                weight[i][j] = abs(pos[i].x - pos[j].x) + abs(pos[i].y - pos[j].y);

        int shortest = TSP(0, 1);
        cout << "#" << cur++ << " " << shortest << "\n";
    }
}

'Algorithm > Dynamic Programming' 카테고리의 다른 글

[백준 12865번] 평범한 배낭 (C++)  (0) 2022.05.09
[백준 4883번] 삼각 그래프 (C++)  (0) 2022.05.06
[백준 11057번] 오르막 수 (C++)  (0) 2022.05.05
[백준 9465번] 스티커 (C++)  (0) 2022.05.05
[백준 11052번] 카드 구매하기 (C++)  (0) 2022.05.05
    'Algorithm/Dynamic Programming' 카테고리의 다른 글
    • [백준 12865번] 평범한 배낭 (C++)
    • [백준 4883번] 삼각 그래프 (C++)
    • [백준 11057번] 오르막 수 (C++)
    • [백준 9465번] 스티커 (C++)
    길민호(ethan.mino)
    길민호(ethan.mino)
    💻 호기심 많은 서버 개발자 길민호입니다.

    티스토리툴바