본문 바로가기
알고리즘/백준

[백준 3190번 뱀]

by 익명의 문과 개발자 2024. 11. 28.
728x90
728x90

오늘의 문제는  뱀이다.

 

 

 

처음엔 무조건 완전탐색!

 

시간제한과 입력의 범위를 보아하니 시간적으로는 문제가 없을 것 같았다.

구현을 어떻게 하는가가 이번 문제의 관건!

일단 사과의 자리를 표현해 줄 map [ ][ ]과 뱀의 존재유무를 따질 visited [ ][ ]를 생각했고,

뱀의 꼬리자리좌표를 ed[ ], 머리좌표를 st [ ], 뱀이 지나간 곳을 담아줄 Queue q 정도 생각했다.

또한 걸린 시간(답안)을 sec배열에 담아주었고 방향을 dr [ ], dc [ ], way(인덱스용)으로 파악해 주었다.

뱀의 방향은 idx와 시간 arr, 방향 arr 이렇게 3가지로 파악 및 갱신해 주었다.

 

글을 읽고 구현을 시작했다!

코드는 다음과 같다.

( 코드가 너무 커 보인다면 "Ctrl + 스크롤 내리기" 하면 잘 보여요! )

( 초기화는 "Ctrl + 0" / 다시 확대는 "Ctrl + 스크롤 올리기" )

import java.util.*;
import java.io.*;

public class Main {
    public static void main(String [] args)throws IOException{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        int N = Integer.parseInt(br.readLine()); // 맵의 크기
        int K = Integer.parseInt(br.readLine()); // 사과의 갯수

        int [][] map = new int [N+1][N+1]; // map 선언
        int [][] visited = new int [N+1][N+1]; // visited 선언
        Queue<int []> q = new LinkedList<>(); // 뱀자리 넣어줄 큐선언
        int [] st = {1, 1}; // 머리
        int [] ed = {1, 1}; // 꼬리
        int sec = 0; // 시간
        int [] dr = {0, 1, 0, -1}; // 4방탐색 좌표와 정보
        int [] dc = {1, 0, -1, 0};
        int way = 0;

        StringTokenizer stringT;
        for(int i = 0; i<K; i++){ // 사과를 map에 1이라 표시해주기
            stringT = new StringTokenizer(br.readLine());

            int x = Integer.parseInt(stringT.nextToken());
            int y = Integer.parseInt(stringT.nextToken());

            map[x][y] = 1;
        }

        int L = Integer.parseInt(br.readLine()); // 방향전환 L번
        int [] secArr = new int [L];
        String [] wayArr = new String [L];
        int idx = 0;
        for(int i = 0; i<L; i++){ // 각 해당 정보 담아주기
            stringT = new StringTokenizer(br.readLine());

            secArr[i] = Integer.parseInt(stringT.nextToken());
            wayArr[i] = stringT.nextToken();
        }

        visited[1][1] = 1; // 시작은 항상 좌상단이기 때문에 미리 방문처리
        while(true){ // 시작 !
            sec++; // 일단 시간 ++
            st[0] += dr[(way + 4) % 4]; // 향하고있는 방향으로 머리를 1칸 이동!
            st[1] += dc[(way + 4) % 4];
            
            // 만약 범위를 벗어나거나 이미 몸통이 존재하는곳에 머리가 닿으면 break
            if(st[0] <= 0 || st[1] <= 0 || st[0] > N || st[1] > N || visited[st[0]][st[1]] == 1){
                break;
            }
            
            // 위 조건이 아니면 방문표시하고 큐에 해당 좌표 넣어준다.
            visited[st[0]][st[1]] = 1;
            q.offer(new int [] {st[0], st[1]});
            
            // 사과가 존재하지 않는다면?
            if(map[st[0]][st[1]] == 0){
                visited[ed[0]][ed[1]] = 0; // 지금 꼬리자리 방문없애고
                int [] temp = q.poll(); // 지나온곳이 차례로 담겨있는 큐에서 하나꺼내
                ed[0] = temp[0]; // 꼬리의 좌표를 갱신해준다.
                ed[1] = temp[1];
            }

            if(idx < L && sec == secArr[idx]){ // idx가 L범위고 해당 idx의 secArr과 같다면?
                if(wayArr[idx].equals("D")){ // 좌로갈지 우로갈지 파악해주고 way에 수정!
                    way += 1;
                }else{
                    way -= 1;
                }
                idx++;
            }
        }
        
        System.out.println(sec); // 출력
    }
}

 

결과는..? Index 범위 오류가 났다 ㅎ

엥.. 왜지 눈을 씻고 찾아봐도 못 찾다가 결국 질문게시판에 들어서게 되었고,,

반례가 대부분 맞던 와중 반례를 찾아주는 사이트를 만나 이유를 알게 되었다.

 

https://testcase.ac/

 

Testcase AC

총 231개의 백준 문제에 대해 반례를 찾을 수 있습니다. 찾고 있는 문제가 없나요?

testcase.ac

 

신기한 사이트 ,, 아직 베타단계지만 종종 확인할 것 같다. 광고 아님

 

아무튼, 위 코드에서의 문제는? while문 하단의 way갱신하는 부분이었다.

            if(idx < L && sec == secArr[idx]){
                if(wayArr[idx].equals("D")){
                    way = (way + 1) % 4;
                }else{
                    way = (way - 1) % 4;
                }
                idx++;
            }

처음의 코드에선 way가 계속 더해지거나 계속 빼질 수 있었다.

이런 실수를,,ㅎ

 

아무튼 매번 더할 때에도 모듈러 연산을 통해서 음수값이 나오지 않게 해 줌으로써

문제를 맞혔다!

 

궁금한 점이 있거나 보충할 점이 있다면 언제든 댓글 부탁드립니다 ~

 

https://www.acmicpc.net/problem/3190

 

 

728x90

'알고리즘 > 백준' 카테고리의 다른 글

[백준 1735번 분수 합]  (2) 2024.12.04
[백준 13241번 최소공배수]  (1) 2024.12.04
[백준 10844번 쉬운 계단 수]  (1) 2024.09.13
[백준 15486번 퇴사 2]  (0) 2024.09.11
[백준 2193번 이친수]  (0) 2024.09.06