https://www.acmicpc.net/problem/10971
문제
외판원 순회 문제는 영어로 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 |