[백준][10971번] 외판원 순회 2
Updated:
문제 URL
https://www.acmicpc.net/problem/10971
나의 풀이
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;
public class Main {
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
public static void main(String[] args) throws IOException {
int n = Integer.parseInt(br.readLine());
int[][] w = new int[n][n]; // cost[i][j] - i에서 j까지 가는데 발생하는 비용
int[] visit = new int[n]; // 도시를 방문해야하는 순서
for (int i = 0; i < n; i++) {
StringTokenizer st = new StringTokenizer(br.readLine());
for (int j = 0; j < n; j++) {
w[i][j] = Integer.parseInt(st.nextToken());
}
}
//초기화
for (int i = 0; i < n; i++) {
visit[i] = i;
}
int answer = Integer.MAX_VALUE;
do {
boolean ok = true;
int sum = 0;
for (int i = 0; i < n - 1; i++) {
int cost = w[visit[i]][visit[i + 1]];
if (cost == 0) {
ok = false;
break;
} else {
sum += cost;
}
}
if (ok && w[visit[n - 1]][visit[0]] != 0) {
sum += w[visit[n - 1]][visit[0]];
if (sum < answer) {
answer = sum;
}
}
} while (next_permutation(visit));
System.out.println(answer);
}
public static boolean next_permutation(int[] a) {
int i = a.length - 1;
while (i > 0 && a[i - 1] >= a[i]) {
i -= 1;
}
if (i <= 0) {
return false;
}
int j = a.length - 1;
while (a[j] <= a[i - 1]) {
j -= 1;
}
int temp = a[i - 1];
a[i - 1] = a[j];
a[j] = temp;
j = a.length - 1;
while (i < j) {
temp = a[i];
a[i] = a[j];
a[j] = temp;
i += 1;
j -= 1;
}
return true;
}
}
다른풀이(C++)(1고정) **
시작점을 1로 고정한 풀이다. (중요!!!!)
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
int a[20][20];
int main(){
int n;
scanf("%d",&n);
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
scanf("%d",&a[i][j]);
}
}
vector<int> d(n);
for (int i=0; i<n; i++) {
d[i] = i;
}
int ans=2147483647;
do {
bool ok = true;
int sum = 0;
for (int i=0; i<n-1; i++) {
if (a[d[i]][d[i+1]] == 0) {
ok = false;
} else {
sum += a[d[i]][d[i+1]];
}
}
if (ok && a[d[n-1]][d[0]] != 0) {
sum += a[d[n-1]][d[0]];
if (ans > sum) ans = sum;
}
//d.begin()+1 하는 부분이 다르다.(1 고정)
} while (next_permutation(d.begin()+1, d.end()));
printf("%d\n",ans);
return 0;
}
다른 풀이**
시작점을 1로 고정한 풀이다. (중요!!!!)
import java.util.*;
public class Main {
public static boolean next_permutation(int[] a) {
int i = a.length-1;
while (i > 0 && a[i-1] >= a[i]) {
i -= 1;
}
if (i <= 0) {
return false;
}
int j = a.length-1;
while (a[j] <= a[i-1]) {
j -= 1;
}
int temp = a[i-1];
a[i-1] = a[j];
a[j] = temp;
j = a.length-1;
while (i < j) {
temp = a[i];
a[i] = a[j];
a[j] = temp;
i += 1;
j -= 1;
}
return true;
}
public static void main(String args[]) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[][] a = new int[n][n];
for (int i=0; i<n; i++) {
for (int j=0; j<n; j++) {
a[i][j] = sc.nextInt();
}
}
int[] d = new int[n];
for (int i=0; i<n; i++) {
d[i] = i;
}
int ans = Integer.MAX_VALUE;
do {
//이부분이 달라짐 !
// d[0] 1부분을 고정하기 위한 부분
if (d[0] != 0) break;
boolean ok = true;
int sum = 0;
for (int i=0; i<n-1; i++) {
if (a[d[i]][d[i+1]] == 0) {
ok = false;
} else {
sum += a[d[i]][d[i+1]];
}
}
if (ok && a[d[n-1]][d[0]] != 0) {
sum += a[d[n-1]][d[0]];
if (ans > sum) {
ans = sum;
}
}
} while(next_permutation(d));
System.out.println(ans);
}
}
느낀점
‘한 도시에서 시작해서 N개의 모든도시를 거쳐 다시 원래 도시로 돌아오려고 한다. (한번 갔던 도시로는 다시 갈 수 없다.)’
라는 두가지 힌트로 순열을 이용하는 문제 라고 유추해볼 수 있다.
또한 순열은 O(N*N!)이라는 많은 비용이 들기때문에 문제의 크기를 따져봐야한다.
문제의 크기 : 2<=N<=10 이므로 모든 경우를 다해봐도 된다!
- 중요!!! 모든 순서를 만들필요없다. 왜냐하면, 1,2,3,4 2,3,4,1 3,4,1,2 4,1,2,3 위 4가지 경우는 모두 같은 경우이다. 다시 시작한 도시로 돌아가야 하기떄문이다. 따라서 시작점을 1로 고정해도된다.
–> 시간복잡도 O(N!)으로 단축가능
Leave a comment