Scanner함수 next(), nextLine() 차이

알고리즘을 풀다보면 예상했던것과 다르게 입력을 받는 경우가 발생한다. 그 중 개행문자('\n')를 먼저 읽어들여 입력한 문자열을 읽어들이지 못하는 경우가 발생한다.

예를 들어,

Scanner sc = new Scanner(System.in);

int a = sc.nextInt();
String b = sc.next();
String c = sc.nextLine();

System.out.println(a);
System.out.println(b);
System.out.println(c);

위 코드에서의 입력과 출력은 아래와 같다.


그 이유는 next() 함수는 문자단위로 입력을 받으며, nextLine() 함수는 개행문자('\n')가 나올 때 까지의 한 줄을 입력받기 때문이다. 즉, b에서는 문자 그대로 '1234'를 입력받지만, c에서는 1234를 입력하기 전에 입력한 개행문자가 저장이 되는 것이다.

또한 next()는 '문자' 단위로 공백을 입력받지 않고 공백 앞뒤의 문자를 입력받는다. 입출력 예시는 아래와 같다.



'JAVA' 카테고리의 다른 글

[JAVA] 조합(Combination) 구현  (0) 2018.11.23
[JAVA] ArrayList 배열로 바꾸기  (0) 2018.11.21
[JAVA] 입력 클래스  (0) 2018.10.10
[JAVA] 이진탐색트리  (1) 2018.10.09

[JAVA] 백준 14503 : 로봇 청소기


문제

로봇 청소기가 있는 장소 N x M 은 빈칸(0) 또는 벽(1)으로 이뤄져있다. 일정한 규칙을 가지고 움직이는 로봇청소기를 이용할 때 청소한 영역의 개수를 구하는 문제이다.로봇청소기의 작동 규칙은 아래와 같다.

    1. 현재 위치를 청소한다.

    1. 현재 위치에서 현재 방향을 기준으로 왼쪽방향부터 차례대로 탐색을 진행한다.

      1) 왼쪽 방향에 아직 청소하지 않은 공간이 존재한다면, 그 방향으로 회전한 다음 한 칸을 전진하고 1번 부터 진행한다. 2) 왼쪽 방향에 청소할 공간이 없다면, 그 방향으로 회전하고 2번으로 돌아간다. 3) 네 방향 모두 청소가 이미 되어있거나 벽인 경우에는, 바라보는 방향을 유지한 채로 한 칸 후진을​ 하고 2번으로 돌아간다. 4) 네 방향 모두 청소가 이미 되어있거나 벽이면서, 뒤쪽 방향이 벽이라 후진도 할 수 없는 경우에는 작동을 멈춘다.


접근방법

- 조건을 그래도 코드로 옮기면 된다. - 청소기의 방향인 북(0), 동(1), 남(2), 서(3) 에서 왼쪽을 보게되면 서(3), 북(0), 동(1), 남(2)을 바라보게 되는데, 이는 switch-case 구문보다 각 방향값에서 1을 빼주는 방법을 사용해 더 깔끔하게 코드를 짤 수 있다.(효근짱b) - 청소기가 네 방향을 모두 탐색한 것은 stay_time 이라는 변수를 두어 해결하였다.


소스코드

import java.util.Scanner;

public class Main{

   static int N;
   static int M;
   static int map[][];
   static int cur_dir;

   static class Pos{ int r; int c; }

   public static int changDir(int dir){
       return (dir == 0)? 3 : dir-1;
  }

   public static Pos changePos(int dir, Pos pos){
       Pos next_pos = new Pos();
       next_pos.r = pos.r;
       next_pos.c = pos.c;

       switch (dir){
           case 0: --next_pos.r; break;    // 북
           case 1: ++next_pos.c; break;    // 동
           case 2: ++next_pos.r; break;    // 남
           case 3: --next_pos.c; break;    // 서
      }
       return next_pos;
  }

   public static Pos backPos(int dir, Pos pos){
       Pos next_pos = new Pos();
       next_pos.r = pos.r;
       next_pos.c = pos.c;

       switch (dir){
           case 0: ++next_pos.r; break;    // 북
           case 1: --next_pos.c; break;    // 동
           case 2: --next_pos.r; break;    // 남
           case 3: ++next_pos.c; break;    // 서
      }
       return next_pos;
  }

   public static int cleaning(int map[][], int N, int M, Pos start){
       int result = 0;

       Pos cur_pos = new Pos();
       Pos before_pos = new Pos();
       cur_pos.c = before_pos.c = start.c;
       cur_pos.r = before_pos.r = start.r;

       int stay_time = 0;
       while(true){
           // 1. 현재 위치를 청소한다.
           if(map[cur_pos.r][cur_pos.c] == 0){
               map[cur_pos.r][cur_pos.c] = 2;
               ++result;
               //printarr(map);
          }

           // 2. 현재 위치에서 현재방향을 기준으로 왼쪽부터 탐색을 진행한다.
           cur_dir = changDir(cur_dir);
           Pos search_pos = changePos(cur_dir, cur_pos);
           ++stay_time;

           // 2-1. 왼쪽방향에 아직 청소하지 않은 공간이 있다면 청소
           if(map[search_pos.r][search_pos.c] == 0){
               cur_pos.r = search_pos.r;   // 현재 위치 변경
               cur_pos.c = search_pos.c;

               stay_time = 0;          // stay time 초기화
          }

           if(stay_time == 4){
               search_pos = backPos(cur_dir, cur_pos);
               // 뒤쪽이 벽이면
               if(map[search_pos.r][search_pos.c] == 1){
                   break;
              }else{
                   // 2-3. 후진
                   cur_pos.r = search_pos.r;
                   cur_pos.c = search_pos.c;
                   stay_time = 0;
              }
          }
      }

       return result;
  }

   private static void printarr(int arr[][]){
       System.out.println();
       for(int i=1; i<arr.length-1; i++){
           for(int j=1; j<arr[0].length-1; j++)
               System.out.print(map[i][j] + " ");
           System.out.println();
      }
  }

   public static void main(String[] args) {
       Scanner sc = new Scanner(System.in);
       N = sc.nextInt();
       M = sc.nextInt();

       map = new int[N+2][M+2];
       for(int i=0; i<N+2; i++)
           for(int j=0; j<M+2; j++)
               map[i][j] = 1;

       Pos start = new Pos();
       start.r = sc.nextInt() + 1;
       start.c = sc.nextInt() + 1;
       cur_dir = sc.nextInt();

       for(int i=1; i<=N; i++)
           for(int j=1; j<=M; j++)
               map[i][j] = sc.nextInt();

       int result = cleaning(map, N, M, start);
       System.out.println(result);
  }
}


'알고리즘' 카테고리의 다른 글

백준15684 : 사다리 조작  (0) 2018.11.21
백준14889 : 스타트와 링크  (0) 2018.11.16
[JAVA] 백준 3055 : 탈출  (0) 2018.09.27
[JAVA] 백준 11559 : 뿌요뿌요  (0) 2018.09.20
[JAVA] 백준 3190 : 뱀  (1) 2018.09.18

[JAVA] 백준 3190 : 뱀


문제

지도에 사과가 놓여있고, 뱀은 명령에 따라 정해진 방향으로 1초에 한 번 씩 움직인다. 뱀이 머리를 움직인 곳에 사과가 있으면 꼬리는 그대로 있으면서 몸의 길이가 늘어나고, 사과가 없으면 꼬리가 있는 칸은 비워줘야한다. 

  • 뱀의 처음 몸길이는 1이다.

  • 뱀의 처음위치는 (1,1)이다.

  • 뱀의 처음 이동방향은 오른쪽이다.

  • 사과는 먹고나면 없어진다.

  • 명령은 L, D가 있으며 L은 왼쪽으로, D는 오른쪽으로 90도 방향을 트는 것을 말한다.

  • 예를 들어 현재 방향이 오른쪽이면서 명령이 (3, D)라면, 3초까지 오른쪽으로 이동한 뒤에 4초부터 방향을 90도 틀어 아래로 움직인다.


접근방법

  1. N x N 공간에서 벽을 설정해주기 위해 (N+2) x (N+2) 배열을 만든다.

  2. 공간에서 빈칸은 0, 사과는 1, 벽은 2라고 정해놓고 벽을 따로 설정해준다.

// 벽 세팅
for(int i=0; i<N+2; i++)
for(int j=0; j<N+2; j++)
if(i==0 || j==0 || i==N+1 || j==N+1)
map[i][j] = 2;
  1. 명령어는 X초에 명령 'L' 혹은 'D'가 주어지므로 instruct[X] = 'L' 형식으로 저장한다. 시간을 인덱스로 사용하면 계속해서 경과시간을 나타내는 변수인 time이 증가할 때 참고하기 편하다.

// 명령어 저장
for(int i=0; i<L; i++)
  instruct[sc.nextInt()] = sc.next().charAt(0);
  1. 뱀이 사과를 먹지 않으면 꼬리부터 없어지기 때문에 FIFO방식의 큐를 이용해 뱀의 몸을 저장한다. 뱀은 머리를 움직일 때 마다 머리가 있는 위치를 큐에 넣어주고, 뱀의 머리가 있는 장소에 사과가 있다면 큐에서 꼬리를 꺼내준다. 또한 뱀의 몸 어느 곳이라도 머리가 부딪히면 게임이 끝나도록 하기 위해 큐에 넣을 때에는 해당 공간을 벽과 동일한 2로 변경해준다. 꼬리를 poll() 할 때 역시 빈칸이 되도록 0으로 변경해준다.

  1. 방향 전환은 로봇청소기(14503)과 같이 규칙을 이용한다.

private static int changeDir(int cur_dir, char instruct){
   int next_dir;
   if(instruct == 'D')
       next_dir = (cur_dir==3) ? 0 : ++cur_dir;
   else
       next_dir = (cur_dir==0)? 3 : --cur_dir;

   return next_dir;
}

- 즉, 북(↑) 동(→) 남(↓) 서(←)0 1 2 3 으로 정하고, 오른쪽으로 90도 꺾어져 이동할 때에는 1씩 증가하고, 왼쪽으로 꺾어질 때에는 1씩 감소하는 규칙을 이용한다. (효근짱!b)

  1. 처리하는 순서는 다음과 같다. 1) 시간을 카운트한다. 2) 뱀의 머리 위치를 변경해주고 해당 위치를 큐에 넣는다. 3) 뱀의 머리 위치에 사과가 있는지 확인한다. - 사과가 있다면 아무일도 일어나지 않는다. - 사과가 없다면 큐를 poll() 해준다. 4) 해당 시간에 방g전환 명령이 있는지 확인한다. 명령이 있다면 방향을 바꿔준다.


소스코드

import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;

public class Main{

   static int dr[] = {-1 ,0, 1, 0};
   static int dc[] = {0, 1, 0, -1};

   static class Pos{
       int r;
       int c;
       public Pos(int r, int c){this.r = r; this.c = c;}
  }

   private static int changeDir(int cur_dir, char instruct){
       int next_dir;
       if(instruct == 'D')
           next_dir = (cur_dir==3) ? 0 : ++cur_dir;
       else
           next_dir = (cur_dir==0)? 3 : --cur_dir;

       return next_dir;
  }

   private static Pos getNextPos(Pos pos, int dir){
       Pos next_pos = new Pos(pos.r, pos.c);
       switch (dir){
           case 0: --next_pos.r; break;
           case 1: ++next_pos.c; break;
           case 2: ++next_pos.r; break;
           case 3: --next_pos.c; break;
      }
       return next_pos;
  }


   public static void main(String[] args) {
       Scanner sc = new Scanner(System.in);

       int N = sc.nextInt();   // 보드 크기 (N x N)
       int K = sc.nextInt();   // 사과 개수
       int L;                  // 명령어 개수
       int time = 0;           // 시간초
       int dir = 1;            // 이동 방향 (북-0, 동-1, 남-2, 서-3)

       Queue<Pos> baam = new LinkedList<>();   // 뱀의 몸 좌표를 넣을 큐
       int map[][] = new int[N+2][N+2];        // 보드 (0-빈칸, 1-사과, 2-벽)
       char instruct[] = new char[100001];     // 명령

       // 벽 세팅
       for(int i=0; i<N+2; i++)
           for(int j=0; j<N+2; j++)
               if(i==0 || j==0 || i==N+1 || j==N+1)
                   map[i][j] = 2;
       // 사과 세팅
       for(int i=0; i<K; i++)
           map[sc.nextInt()][sc.nextInt()] = 1;

       L = sc.nextInt();
       // 명령어 저장
       for(int i=0; i<L; i++)
           instruct[sc.nextInt()] = sc.next().charAt(0);

       Pos cur_pos = new Pos(1, 1);
       baam.offer(cur_pos);
       map[cur_pos.r][cur_pos.c] = 2;

       while(true){
           ++time;
           // 뱀의 머리 위치 이동
           cur_pos.r += dr[dir];
           cur_pos.c += dc[dir];
           //cur_pos = getNextPos(cur_pos, dir);

           // 벽이나 뱀의 몸을 만났을 경우 게임 종료
           if(map[cur_pos.r][cur_pos.c] == 2 ){
               break;
          }

           // 빈칸인 경우 마지막 칸 꼬리를 비워줌
           if(map[cur_pos.r][cur_pos.c] == 0){
               Pos retail = baam.poll();
               map[retail.r][retail.c] = 0;
          }
           // 머리를 큐에 넣고 맵의 변수 변경
           baam.offer(cur_pos);
           map[cur_pos.r][cur_pos.c] = 2;

           // 방향전환
           if(instruct[time] == 'D' || instruct[time] == 'L')
               dir = changeDir(dir, instruct[time]);
      }

       System.out.println(time);
  }
}

- 예제 2번의 답을 계속 20이라고 생각했던 이유는 뱀이 1초때에 (1,1)에 있고, 2초때 (1,2)로 이동한다고 생각했기 때문. 뱀은 처음에 (1,1)에 있고 1초 때 (1,2)로 이동하므로 time을 0으로 초기화해줘서 해결 할 수 있었다(성희짱!b) - 시뮬레이션 문제는 특히 푸는데 시간이 많이 걸리는 것 같다. 풀이시간을 계속 줄여나갈 것!

'알고리즘' 카테고리의 다른 글

백준15684 : 사다리 조작  (0) 2018.11.21
백준14889 : 스타트와 링크  (0) 2018.11.16
[JAVA] 백준 3055 : 탈출  (0) 2018.09.27
[JAVA] 백준 11559 : 뿌요뿌요  (0) 2018.09.20
[JAVA] 백준 14503 : 로봇 청소기  (0) 2018.09.18

+ Recent posts