숨바꼭질
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;
public class Main {
public static int N, K;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
K = Integer.parseInt(st.nextToken());
bfs();
}
public static void bfs(){
Queue<Integer> q = new LinkedList<>();
int[] visited = new int[200001];
q.offer(N);
visited[N] = 1;
int cnt = 0;
while(!q.isEmpty()){
int size = q.size();
for(int i = 0; i < size; i++){
int cur = q.poll();
if(cur == K) {
System.out.println(cnt);
return;
}
if(cur + 1 < 200001 && visited[cur + 1] == 0) {
visited[cur] = 1;
q.offer(cur + 1);
}
if(cur - 1 >= 0 && visited[cur - 1] == 0) {
visited[cur] = 1;
q.offer(cur - 1);
}
if(cur * 2 < 200001 && visited[cur * 2] == 0) {
visited[cur] = 1;
q.offer(cur * 2);
}
}
cnt++;
}
}
}
숨바꼭질 4
시작점이 0일때나 시작점과 끝점이 같을 때 처리하는 반례 때문에 꽤나 애를 먹었다.
배열을 방문만 처리하는 배열과 이전노드를 저장하는 배열 두개를 쓸게 아니면 이 방법이 유일한것같다.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;
public class Main {
public static int N, K, ans = 0;
public static int[] visited = new int[100001];
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
K = Integer.parseInt(st.nextToken());
if(N == K){
System.out.println(ans);
System.out.println(K);
} else{
Arrays.fill(visited, -1);
bfs();
}
}
public static void bfs(){
Queue<Integer> q = new LinkedList<>();
q.offer(N);
visited[N] = -2;
while(!q.isEmpty()){
int size = q.size();
for(int i = 0; i < size; i++){
int cur = q.poll();
if(cur == K) {
System.out.println(ans);
route();
return;
}
if(cur + 1 < 100001 && visited[cur + 1] == -1) {
visited[cur + 1] = cur;
q.offer(cur + 1);
}
if(cur - 1 >= 0 && visited[cur - 1] == -1) {
visited[cur - 1] = cur;
q.offer(cur - 1);
}
if(cur * 2 < 100001 && visited[cur * 2] == -1) {
visited[cur * 2] = cur;
q.offer(cur * 2);
}
}
ans++;
}
}
public static void route() {
Stack<Integer> st = new Stack<>();
int cur = K;
while(cur != -2){
st.push(cur);
cur = visited[cur];
}
StringBuilder sb = new StringBuilder();
while(!st.isEmpty()){
sb.append(st.pop()).append(' ');
}
System.out.println(sb);
}
}
이모티콘
빠르게 풀었는데 37퍼에서 오류가 났다.
이유를 생각해보니 방문배열을 1차원으로 그냥 화면에 있는 이모티콘만 생각했을때 클립보드에 있는 이모티콘의 수도 같이 생각해야된다고 판단해서 2차원배열로 만들어주었다.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;
public class Main {
public static int S;
public static int[][] visited = new int[2001][2001];
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
S = Integer.parseInt(br.readLine());
bfs();
}
public static void bfs(){
Queue<int []> q = new LinkedList<>();
q.offer(new int[] {1, 1});
visited[1][1] = 1;
int cnt = 1;
while(!q.isEmpty()){
int size = q.size();
for(int i = 0; i < size; i++){
int cur[] = q.poll();
if(cur[0] == S){
System.out.println(cnt);
return;
}
// 1.화면에 있는 이모티콘을 모두 복사해서 클립보드에 저장한다.
if(cur[0] != cur[1]) {
q.offer(new int[]{cur[0], cur[0]});
}
// 2.클립보드에 있는 모든 이모티콘을 화면에 붙여넣기 한다.
if(cur[0] + cur[1] <= 2000 && visited[cur[0] + cur[1]][cur[1]] == 0){
visited[cur[0] + cur[1]][cur[1]] = 1;
q.offer(new int[] {cur[0] + cur[1], cur[1]});
}
// 3.화면에 있는 이모티콘 중 하나를 삭제한다.
if(cur[0] - 1 > 0 && visited[cur[0] - 1][cur[1]] == 0){
visited[cur[0] - 1][cur[1]] = 1;
q.offer(new int[] {cur[0] - 1, cur[1]});
}
}
cnt++;
}
}
}
숨바꼭질 3
처음엔 단순 BFS 로 풀이했는데 반례가 존재할꺼같아 GPT 의 도움을 받아 다시 풀었다.
BFS 로 풀어도 이 문제가 풀리긴 하지만 좀 더 정확한 풀이를 위해선 0 - 1 BFS 로 풀었다.
간선이 0과 1밬에 존재하지 않는 최단거리 탐색 방법이다.
만약 0과 1 말고 다른 경우가 존재한다면 다익스트라로 푸는것이 맞는것같다.!
- 0-1 BFS (Deque)
- 각 간선을 O(1) 로 처리 가능
- 전체 복잡도: O(V + E)
- 여기서는 정점 V=100,001, 간선은 최대 3V 정도 → O(3×10⁵) 수준
- 실전에서 가장 빠름
- 다익스트라 (PriorityQueue)
- 매 삽입/삭제가 O(log V)
- 전체 복잡도: O(E log V) ≈ 3×10⁵ × log(10⁵)
- log(10⁵) ≈ 17 → 연산량이 수백만 단위
- 충분히 AC 나오지만 Deque보다 느림
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;
public class Main {
static final int MAX = 100000;
public static int N, K;
public static int[] dist;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
K = Integer.parseInt(st.nextToken());
if(N >= K){
System.out.println(N - K);
return;
}
dist = new int[MAX + 1];
Arrays.fill(dist, Integer.MAX_VALUE);
bfs();
}
public static void bfs(){
Deque<Integer> dq = new ArrayDeque<>();
dist[N] = 0;
dq.offer(N);
while(!dq.isEmpty()){
int x = dq.pollFirst();
if(x == K){
System.out.println(dist[x]);
return;
}
int nx = x * 2;
if(nx <= MAX && dist[nx] > dist[x]) {
dist[nx] = dist[x];
dq.offerFirst(nx);
}
nx = x + 1;
if(nx <= MAX && dist[nx] > dist[x] + 1) {
dist[nx] = dist[x] + 1;
dq.offerLast(nx);
}
nx = x - 1;
if(nx >= 0 && dist[nx] > dist[x] + 1) {
dist[nx] = dist[x] + 1;
dq.offerLast(nx);
}
}
}
}
알고스팟
도착지점까지 이동하려면 몇초가 걸리는지 계산하는 문제가 아닌 벽을 몇개를 부수면 갈 수 있는지 계산하는 문제
예전에 풀었던 벽부수고 이동하기랑 비슷해 보였다.
그 문제는 이차원 배열을 이용하여 벽을 부순횟수와 위치를 방문배열에 동시에 저장해야하는데 그런느낌이랑은 좀 달랐다.
왜냐하면 벽을 부수는 횟수는 정해지지 않았고 벽을 부순 횟수를 구하는게 중요한 문제이기 때문이다.
가장 쉽게 풀 수 있는 방법은 위치와 몇번 부쉈는지 계산하며 방을 이동한다. 아까와 비슷한 0 - 1 BFS 로 풀 수 있을꺼같다.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;
public class Main {
public static int M, N;
public static int[][] map, dist;
public static int[] dr = {-1, 0, 1, 0};
public static int[] dc = {0, 1, 0, -1};
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
M = Integer.parseInt(st.nextToken());
N = Integer.parseInt(st.nextToken());
map = new int[N][M];
dist = new int[N][M];
for(int i = 0; i < N; i++){
String str = br.readLine();
for(int j = 0; j < M; j++){
map[i][j] = str.charAt(j) - '0';
}
}
for(int i = 0; i < N; i++){
Arrays.fill(dist[i], Integer.MAX_VALUE);
}
bfs();
}
public static void bfs(){
Deque<int[]> dq = new ArrayDeque<>();
dist[0][0] = 0;
dq.offer(new int[] {0, 0});
while(!dq.isEmpty()){
int[] cur = dq.pollFirst();
int r = cur[0];
int c = cur[1];
if(r == N - 1 && c == M - 1){
System.out.println(dist[r][c]);
return;
}
for(int d = 0; d < 4; d++){
int nr = r + dr[d];
int nc = c + dc[d];
if(nr < 0 || nr >= N || nc < 0 || nc >= M) continue;
if(map[nr][nc] == 0 && dist[nr][nc] > dist[r][c]) {
dist[nr][nc] = dist[r][c];
dq.offerFirst(new int[] {nr, nc});
}
if(map[nr][nc] == 1 && dist[nr][nc] > dist[r][c] + 1) {
dist[nr][nc] = dist[r][c] + 1;
dq.offerLast(new int[] {nr, nc});
}
}
}
}
}
이전에는 풀고나서 다른 블로그에서 더 잘 푼 사람이나 다른방법으로 푼게 있으면 보고 피드백을 했는데 요즘은 그냥 gpt 한테 물어보는게 더 정확하고 깔끔하게 푸는것같다.
'코딩테스트 > JAVA' 카테고리의 다른 글
| [백준 JAVA] 알고리즘 재활훈련 (기초) (0) | 2025.09.17 |
|---|---|
| [백준 JAVA] 회귀한 프로그래머의 최소신장트리 다시풀기 (0) | 2025.09.16 |
| [백준 JAVA] 회귀한 프로그래머의 그래프 1 다시풀기 (0) | 2025.09.05 |
| [백준 JAVA] 회귀한 프로그래머의 재귀 다시풀기 (0) | 2025.08.14 |
| [백준 JAVA] 회귀한 프로그래머의 순열 응용 문제 다시 풀기 (3) | 2025.08.04 |