하루하루 꾸준히, 인생은 되는대로

알고리즘

백준 10971 외판원 순회 2 C++

긤효중 2022. 7. 6. 10:53

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

 

10971번: 외판원 순회 2

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

www.acmicpc.net


문제

외판원 순회 문제는 영어로 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로 가기 위한 비용을 나타낸다.

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


출력

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


문제는 1번부터 N번까지 번호가 적힌 도시가 있고 도시를 사이에 길이 있다.

이제 외판원이 한 도시에서 출발해 N개의 도시를 거쳐서 다시 출발했던 도시로 돌아오는 경로를 짜는데,

 

최소의 비용을 들여서 여행을 하고자한다.

 

각 도시간의 비용은 행렬 w[i][j]의 형태이다.

 

만약 N이 4이고 1번부터 4번까지 도시가 있다면, 도시를 이동하는 경우의 수는 1,2,3,4,1  

1,2,4,3,1 ......이런식으로 경로가 있을 것이다. 이에 대해서 모든 경우를 찾고 , 최소가 되는 비용이 나올때마다 갱신을 해주면 된다.

 

주의해야 할 점은 비용이 0이라면 도시를 이동할 수 없는 (길이 없는 경우)이므로 이때는, 값이 갱신되지 않는다.

 


#include <iostream>
#include <vector>
using namespace std;

int min(int a,int b){
    if(a<b){
        return a;
    }
    else{
        return b;
    }
}

int n;
int arr[11][11]; //비용(행렬 형태)
int a[11];
bool visited[11];
int ans = 987654321; //여행의 최소비용
vector<int> v;

void dfs(int start){
    if(start == n){
        int sum = 0;
        for(int i = 0;i<n-1;i++){ 
           /*n-1까지 해야하는 이유 ->
           
           1,2,3,4... 1,2,4,3... N이 4 
           일떄 (1,2) (2,3) (3,4)  +  (4,1)까지 검사하면 되니깐 (4,5)는 검사할 필요 x
           */
            
            if(arr[a[i]][a[i+1]] == 0){ //도시를 연결하는 길이 없는 경우 -> 갱신 x
                return;
            }
            sum = sum + arr[a[i]][a[i+1]];
        }
    
      if(arr[a[n-1]][a[0]] != 0){ //원래의 도시로 갈 수 있을 때 값 갱신
           sum = sum + arr[a[n-1]][a[0]];
           ans = min(sum,ans);
      }
     
        return;
        
    }
    for(int i = 0;i<n;i++){
        if(visited[i] == false){
            visited[i] = true;
            a[start] = i;
            dfs(start+1);
            visited[i] = false;
           
        }
    }
}
int main(void){
    cin >> n;
    for(int i = 0;i<n;i++){
        for(int j = 0;j<n;j++){
            cin >> arr[i][j];
        }
    }
    
    dfs(0);
    cout << ans;
}

 

#include <iostream>
#include <vector>
using namespace std;

int min(int a,int b){
    if(a<b){
        return a;
    }
    else{
        return b;
    }
}

int n;
int arr[11][11]; //비용(행렬 형태)
int a[11];
bool visited[11];
int ans = 987654321; //여행의 최소비용
vector<int> v;

void dfs(int start){
    if(start == n){
        int sum = 0;
        for(int i = 0;i<n-1;i++){ 
           /*n-1까지 해야하는 이유 ->
           
           1,2,3,4... 1,2,4,3... N이 4 
           일떄 (1,2) (2,3) (3,4)  +  (4,1)까지 검사하면 되니깐 (4,5)는 검사할 필요 x
           */
            
            if(arr[a[i]][a[i+1]] == 0){ //도시를 연결하는 길이 없는 경우 -> 갱신 x
                return;
            }
            sum = sum + arr[a[i]][a[i+1]];
        }
    
      if(arr[a[n-1]][a[0]] != 0){ //원래의 도시로 갈 수 있을 때 값 갱신
           sum = sum + arr[a[n-1]][a[0]];
           ans = min(sum,ans);
      }
     
        return;
        
    }
    for(int i = 0;i<n;i++){
        if(visited[i] == false){
            visited[i] = true;
            a[start] = i;
            dfs(start+1);
            visited[i] = false;
           
        }
    }
}
int main(void){
    cin >> n;
    for(int i = 0;i<n;i++){
        for(int j = 0;j<n;j++){
            cin >> arr[i][j];
        }
    }
    
    dfs(0);
    cout << ans;
}

'알고리즘' 카테고리의 다른 글

백준 11497 통나무 건너뛰기 C++  (0) 2022.07.11
백준 2491 수열 C++  (0) 2022.07.09
너비 우선 탐색 (BFS, Breadth-First Search)  (0) 2022.07.05
백준 1544 사이클 단어 C++  (0) 2022.07.04
백준 9742 순열 C++  (0) 2022.06.28