일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- Props
- 13549
- 비트코인
- 서버리스
- 모각코
- 설치과정
- Docker-compose
- 너비 우선 탐색
- kubernetes
- kubernets
- 코딩테스트
- Vue
- observability
- alert
- BaaS
- 타원곡선
- k8s
- Jenkins
- 프로그래머스
- cloud
- FAAS
- 숨바꼭질3
- Programmers
- ChangeCipherSpec
- 도커
- golang
- docker
- sia
- 백준
- vue.js
- Today
- Total
작업공간
[BFS] 백준 13549 Java 본문
BFS 를 이용한 문제 풀이
13549번: 숨바꼭질 3
수빈이는 동생과 숨바꼭질을 하고 있다. 수빈이는 현재 점 N(0 ≤ N ≤ 100,000)에 있고, 동생은 점 K(0 ≤ K ≤ 100,000)에 있다. 수빈이는 걷거나 순간이동을 할 수 있다. 만약, 수빈이의 위치가 X일
www.acmicpc.net
문제 조건
* 시간 제한 : 2초
* 메모리 제한 : 512MB
위 조건과 문제 상황을 고려하며 자료구조를 계획했다.
1. 술래와 숨는 사람의 위치 N ,K 는 모두 0 ~ 100,000 의 범위이므로 int로 생성 -> 8bytes
2. Queue에 넣기 위한 Node ( int x, int sec ) 를 필드만 고려했을 때 -> 개당 8bytes
After. 0 ~ 100,000 번지의 방문 체크를 하기위해 boolean[100001] 생성 -> 1bit * 100,001 , 약 12KB
Try 1 ) Location * 2 , Location - 1 , Location + 1 을 순서로 목적지 K 와 비교하며 종료 or 새로운 노드 생성 및 큐에 추가
최소 sec 를 구해야하기 때문에 자식 노드의 순서를 정할 때 sec 가 늘지 않는 Loc * 2를 맨 처음 넣었다.
Loc -1 과 Loc + 1을 어떻게 할까 고민 중에 수가 작아지면 *2 도 고려할 수 있지만 커지면 *2를 고려할 수 있는 경우가 줄어든다는
느낌이 와서 간단한 테스트 케이스를 통해 순서를 정했다.
Test case ) 5 -> 8 로 가려면 ?
1. 5 -> 4 -> 8 : sec = 1 : * 2 를 할 수 있는 경우가 생김
2. 5 -> 6 -> 7 -> 8 : sec = 3 : * 2 를 할 수 없음
▶ Problem ) 직접 만들어놓은 몇가지의 테스트 케이스는 통과하나 굉장히 오래걸린다.
-> x == 1 일 때 자식 노드의 x 는 1*2, 1-1, 1+1 인데 2, 0, 2 이므로 같은 위치를 재방문하는 오류가 있었다.
Try 2 - Clear ) 방문체크를 하는 Boolean 배열을 이용하여 재방문을 하지 않도록 한다.
술래가 지나간 점을 모두 방문체크하여 재방문하지 않도록 한다.
< 동작 과정 >
1. 술래의 위치 N , 목표 위치 K 를 입력받는다.
2. Node ( N , 0 ) 을 root 로 두고 큐에 넣는다.
3. 큐에서 하나씩 꺼내며 *2, -1 , +1을 하였을 때 K와 같고 방문하지 않았다면 sec, sec+1, sec+1 을 리턴하고
같지 않다면 이동한 지점을 방문 체크하고 큐에 해당 지점과 sec / sec+1을 노드로 생성하여 큐에 넣는다.
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
public class boj_13549 {
static int N,K;
static Scanner sc = new Scanner(System.in);
static boolean[] visit;
static final int max = 100001; // visit 0 ~ 100000 까지
static Queue<Node> queue = new LinkedList<>();
public static void main(String[] args) {
visit = new boolean[max];
N = sc.nextInt();
K = sc.nextInt();
visit[N] = true;
System.out.println(bfs(new Node(N,0)));
}
private static int bfs(Node root) {
// X -1 , X +1 , 2 * X 3개의 자식 노드가 생길 수 있음.
if ( root.x == K){return 0;}
queue.add(root);
while(!queue.isEmpty()){
Node n = queue.poll();
// System.out.println("X : " + n.x + " Sec : " + n.sec);
// X * 2 를 했을 때 범위 내에 있을 시 visit 체크 & K와 비교 후 Return Or Queue add 결정
if ( n.x*2 <= max){
if (!visit[n.x*2]){
if ( n.x*2 == K) return n.sec;
else {
visit[n.x*2] = true;
queue.add(new Node(n.x*2,n.sec));
}
}
}
// X - 1 를 했을 때 범위 내에 있을 시 visit 체크 & K와 비교 후 Return Or Queue add 결정
if (n.x>0){
if (!visit[n.x-1]){
if (n.x-1 == K) return n.sec+1;
else {
visit[n.x -1] = true;
queue.add(new Node(n.x-1,n.sec+1));
}
}
}
// X + 1 를 했을 때 범위 내에 있을 시 visit 체크 & K와 비교 후 Return Or Queue add 결정
if ( n.x < max-1){
if (!visit[n.x+1]){
if (n.x+1 == K) return n.sec+1;
else {
visit[n.x+1] = true;
queue.add(new Node(n.x+1,n.sec+1));
}
}
}
}
return -1;
}
static class Node{
int x;
int sec;
Node(int newX, int newSec){
this.x = newX;
this.sec = newSec;
}
}
}
Review
코드를 줄이기위해 방문체크와 노드의 x K 비교를 큐에서 꺼낸 후의 단계에서 진행하도록 해보았는데
이렇게 하게되면 리프 노드에서 하나씩 노드를 더 큐에 추가하기 때문에 메모리를 많이 잡아먹었다.
메모리를 적게하기 위해 새로운 지점을 노드로 생성하여 큐에 추가하기 전 비교를 하도록 하였다.
'알고리즘' 카테고리의 다른 글
[Go] 하노이의 탑 (1) | 2024.01.08 |
---|