geeksforgeeks.org
Hamiltonian Path / geeksforgeeks.org
건이두
2019. 12. 25. 20:13
728x90
Hamiltonian Path / geeksforgeeks.org
- 주의사항
- 1 8 이렇게 되어 있어도, 1,8 8,1 2개의 방향 모두 이동 가능함
- 시작이 항상 1부터가 아니고, 모든 vertex에서 시작할 수 있음
문제 링크 : https://practice.geeksforgeeks.org/problems/hamiltonian-path/0
문제 해설 : https://www.geeksforgeeks.org/hamiltonian-cycle-backtracking-6/
정답 코드 : https://github.com/skysign/WSAPT/blob/master/geeksforgeeks.org/Hamiltonian%20Path/src/GFG.java
import java.util.Scanner;
// Hamiltonian Path / geeksforgeeks.org
// 문제 링크 : https://practice.geeksforgeeks.org/problems/hamiltonian-path/0
// 문제 해설 : https://www.geeksforgeeks.org/hamiltonian-cycle-backtracking-6/
public class GFG {
/**
* 2개의 vertext사이에 edge가 존재할 때, 기존에 방문했던 vertex인지 확인하는 메서드
* @param vertex 방문하려고 하는 vertex 숫자
* @param vertices 지금까지 방문한 순서대로 vertex 숫자
* @param idxVertices vertices에 저장되어 있는 vertex의 갯수
* @return 방문했던 vertex true, 아니면 false
*/
public static boolean isVisited(int vertex, int[] vertices, int idxVertices){
for(int i=1; i<idxVertices; ++i) {
if(vertex == vertices[i])
return true;
}
return false;
}
/**
* @param J 방문한 vertext 숫자
* @param m 2개의 vertex에 edge가 있으면 true, 아니면 false
* @param vertices 방문한 순서대로 vertext 숫자를 저장한 배열
* @param idxVertices vertices에 vertext 숫자를 저장할 인덱스
* @param numOfVertices vertices의 길이, 항상 N+1 입니다.
* @return Hamiltonian Path를 찾았으면 1, 못 찾았으면, 0
*/
public static int path(int J, boolean[][] m, int[] vertices, int idxVertices, int numOfVertices) {
// 마지막 vertex까지 다 찾았으면, 리턴
if(idxVertices == numOfVertices) {
if(m[vertices[idxVertices-1]][0]){
return 1;
}
}
int i=J;
for(int j=1; j<m[0].length; ++j) {
// i vertex에서 j vertex로 가는 길이 있는지 찾고
if(m[i][j]) {
// j vertex가 기존에 방문했던 vertext가 아니면
if(false == isVisited(j, vertices, idxVertices)) {
// 방문한 순서대로 vertices에 j vertex를 저장하고
vertices[idxVertices] = j;
// j vertex에서 방문 가능한 다음번 vertex를 찾아 갑니다.
if(1 == path(j, m, vertices, 1+idxVertices, numOfVertices)) {
return 1;
}
}
}
}
return 0;
}
public static int HamiltonianPath(int N, int M, int[] p) {
int r = 0;
// 문제를 좀 쉽게 풀기 위해서,
// vertex 개수인 N과 m 배열의 인덱스가 서로 같은게 코딩하기도, 코드 읽기도 편하구요,
// 0 번이 있어야, Hamiltonian Path가 있는지 최종 체크하기가 편하기도 합니다.
// 실제로 문제에서, 입력은 받지 않지만, 0 번째 vertex가 있다고 가정합니다.
boolean[][] m = new boolean[N+1][N+1];
int[] vertices = new int[N+1];
// 문제의 마지막 문장이 아래와 같이 끝납니다.
// Then in the next line are M space separated pairs u,v denoting an edge from u to v.
// 마지막 단락을 해석해 보면, u 에서 v 로 가는 edge가 directed 로 있는 것지만,
// 실제로는 아닙니다. 문제 두번째 문장에, 'Give an undirected graph' 로 되어 있기 때문에,
// 1 8 을 입력받으면, 1,8 과 8,1 2개의 방향 모두 이동 가능합니다.
for(int i=0; i<M*2; i+=2) {
m[p[i]][p[i+1]] = true;
m[p[i+1]][p[i]] = true;
}
// 0번째 vertex로 가는 edge는 항상 존재 합니다.
// 즉, 첫번째 vertex에서 마지막 vertex까지 찾은 다음에,
// 마지막 vertext가 0으로 가는길이 있다면, Hamiltonian Path가 존재 합니다.
for(int j=1; j<=N; ++j)
m[j][0] = true;
// 항상 첫번째 시작은 0번째 vertex부터 시작하구요.
vertices[0] = 0;
// 모든 vertex에서 시작할 수 있기 때문에,
// m[0][i] = true해주고
// path를 못 찾았으면
// m[0][i] = false 그다음 i 로 넘어가서 Hamiltonian Path를 찾습니다.
for(int i=1; i<=N; ++i) {
m[0][i] = true;
r = path(0, m, vertices, 1, N+1);
if(r == 1) {
return 1;
}
m[0][i] = false;
}
return r;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int T=sc.nextInt();
while(T-->0) {
int N = sc.nextInt();
int M = sc.nextInt();
int[] a = new int[M*2];
for(int i=0; i<M*2; ++i) {
a[i] = sc.nextInt();
}
int r = HamiltonianPath(N, M, a);
System.out.println(r);
}
}
}
728x90