문제 설명
최단거리의 경로까지 구해야 하는 문제이다.
문제 풀이
숨바꼭질 시리즈를 풀면서 가장 구하고 싶었던게, 최단거리의 경로까지 구하는 것이었다. 그런데 숨바꼭질4에서 딱 이러한 점을 요구하고 있어서 놀랐고, 더욱 풀고싶었다.
처음에 각 큐의 경로를 어떻게 구할지 엄청나게 고민했다. 그래서 생각해낸 방법이...
클래스StepInfo
에List<Integer>
객체인route
를 추가해주는것이었다. 저route
객체에 그동안 지나온 위치를 저장한다.
하지만 각각의q
말고 모든q
에서 꺼낸 값들이 저장되는 문제가 생겼다.ㅠ
그래서 몇시간을 다시 고민하기 시작했다.ㅠ 결국 여러방법을 시도해봤으나 실패해서 인터넷에 나와있는 풀이를 참고했다.
바로배열
에 저장하는 것이었다.
나는 계속리스트
에 저장할 생각만 했어서,배열
에 저장할 생각은 꿈에도 못했다. 앞으로도 좀 더 노력해야 할듯 하다ㅠ
static int[] route = new int[100001];
일단 전역변수로 배열을 선언해주었다.
for(int d = 0; d < 3; d++) {
switch(d) {
case 0:
tempN = n;
tempN += 1;
if(tempN >= 0 && tempN < check.length && check[tempN] == false) {
nextStep = new StepInfo(tempN, stepInfo.step + 1);
q.add(nextStep);
route[tempN] = n;
check[tempN] = true;
}
break;
아직 방문하지 않은 수를
q
에 넣을 때, 방문기록을 저장하는route
에도 저장해준다.
5 > 6
이라 가정하면,route[6] = 5
가 저장된다.
즉, 문제 예제5 17
이 입력되면,5 > 10 > 9 > 18 > 17
순으로 방문하는 것이 최단경로인데.
route[10] = 5
route[9] = 10
route[18] = 9
route[17] = 18
이런식으로route
에 저장된다.
그리고나서 현재 위치n
이 동생의 위치인K
에 도달할 경우,route[N]
에서 부터 시작해, 서로 가리키고 있는 값을 출력해냈다.
if(n == K){
System.out.print(route[N] + " ");
int idx = route[N];
for(int i = 0; i < stepInfo.step; i++){
System.out.print(route[idx] + " ");
idx = route[idx];
}
}
즉,
route[5]
부터 시작해서, 그 값을idx
에 담아주고, 그 다음은route[idx]
를 출력하는 것을 최단거리 수만큼 반복했다.
그랬더니5
와6
이 핑퐁되는 현상이 발생했다 ...
route[5] = 6
이고,route[6] = 5
였기 때문에 생긴 현상이었다..
저거때문에 몇시간을 헤맸는지 모른다ㅠ
분명5
에서4
가 되는게 최단거리의 경로일텐데,,5
에서6
이 된다고 생각했었으니 말이다.
하지만, 여기서route
의 의미를 다시한번 되짚고 갈 필요가 있었다.
route[tempN] = n
의 의미란,tempN > n
이 아니라
반대로n > tempN
으로 간다는 의미였는데, 헷갈려서 기본적은 실수를 하고 있었다ㅠ
즉,route[N]
으로 시작하는 것은시작점에서 출발하겠다
는 의미가 아니라시작점으로 가겠다
였다...ㅠㅠㅠ
if(n == K) {
System.out.println(stepInfo.step);
Stack<Integer> stack = new Stack<>();
stack.push(route[K]);
int idx = route[K];
for(int i = 0; i < stepInfo.step - 1; i++){
stack.push(route[idx]);
idx = route[idx];
}
while(!stack.isEmpty()) {
System.out.print(stack.pop()+" ");
}
System.out.print(K);
}
따라서 아까처럼 시작위치
N
에서부터 출력하는 것이 아닌, 동생의 위치K
에서부터 경로를 따라 출력해주었다.
거꾸로 따라가기 때문에!! 출력은 시작위치에서 하기 위해서Stack
을 사용하였다!
하지만 문제점이 발생했다 ㅠ
맞게 풀었다고 생각했는데, 막상 제출해보니 틀렸다는 결과가 나오고 있었다.
여기서 또 몇 시간을 잡아먹었다ㅠ
반례 이것저것 넣어보았지만 맞는 결과값이 출력되고 있어서 더욱 멘붕이었다...ㅠ
몇 시간을 까먹고나니 눈이 너무 아파서 빠질것같아 다른 사람들에게 도움을 요청했다.
그 결과,5 5
같이N
과K
가 같은 경우에0
과5
하나만 나와야 하는데, 출력이 이상하게 되는 것이었다.
알고보니N
과K
가 같은 케이스는, 바로 정답만 출력하고 끝나야 하는데, 그러지 않고 그 아래까지 쭉 돌아가버려서 저런 이상한 결과가 발생했던 것이었다.
if(N == K) {
System.out.println(stepInfo.step);
System.out.println(N);
return;
}
따라서, 위와 같이
N
과K
가 같은 케이스일때의 로직도 추가해줌으로써 해결했다ㅠ
정말 힘들었던 과정이었다..ㅠㅠㅠㅠ
이렇게 고생하며 느꼈던 점은, 최소 최대 케이스를 꼭 체크해봐야 한다는 것과 가장 간단한 케이스 (오늘같은) 도 확인해봐야 한다는 것을 깨닫게 되었다ㅠㅠㅠㅠ
전체 코드
public class Practice2 {
static int N;
static int K;
static boolean[] check = new boolean[100001];
static int[] route = new int[100001];
public static class StepInfo{
int nowN;
int step;
public StepInfo(int nowN, int step) {
this.nowN = nowN;
this.step = step;
}
}
public static void main(String[] args) {
input();
List<Integer> records = new ArrayList<>();
records.add(N);
StepInfo stepInfo = new StepInfo(N, 0);
Queue<StepInfo> q = new LinkedList<>();
q.add(stepInfo);
hideAndSeek(q);
}
private static void hideAndSeek(Queue<StepInfo> q) {
while(!q.isEmpty()) {
StepInfo stepInfo = q.poll();
int n = stepInfo.nowN;
//check[n] = true;
if(n == K) {
if(N == K) {
System.out.println(stepInfo.step);
System.out.println(N);
return;
}
System.out.println(stepInfo.step);
Stack<Integer> stack = new Stack<>();
stack.push(route[K]);
int idx = route[K];
for(int i = 0; i < stepInfo.step - 1; i++){
stack.push(route[idx]);
idx = route[idx];
}
while(!stack.isEmpty()) {
System.out.print(stack.pop()+" ");
}
System.out.print(K);
}
// +1, -1, *2 셋 중 어느 연산을 할 건지 탐색
StepInfo nextStep;
int tempN;
for(int d = 0; d < 3; d++) {
switch(d) {
case 0:
tempN = n;
tempN += 1;
if(tempN >= 0 && tempN < check.length && check[tempN] == false) {
nextStep = new StepInfo(tempN, stepInfo.step + 1);
q.add(nextStep);
route[tempN] = n;
check[tempN] = true;
}
break;
case 1:
tempN = n;
tempN -= 1;
if(tempN >= 0 && tempN < check.length && check[tempN] == false) {
nextStep = new StepInfo(tempN, stepInfo.step + 1);
q.add(nextStep);
route[tempN] = n;
check[tempN] = true;
}
break;
case 2:
tempN = n;
tempN *= 2;
if(tempN >= 0 && tempN < check.length && check[tempN] == false) {
nextStep = new StepInfo(tempN, stepInfo.step + 1);
q.add(nextStep);
route[tempN] = n;
check[tempN] = true;
}
break;
}
}
}
}
private static void input() {
Scanner sc = new Scanner(System.in);
N = sc.nextInt();
K = sc.nextInt();
}
}
Git gist 주소
https://gist.github.com/ysyS2ysy/2eaf04db26587b2ee4e95a99e95573ad