본문 바로가기

Hub Algorithm/구현

[BOJ] 백준 1022 : 소용돌이 예쁘게 출력하기 (java)

728x90

🧪 1022 소용돌이 예쁘게 출력하기


난이도 : 🌟 골드 3
유형 : 구현

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

 

📝 문제


크기가 무한인 정사각형 모눈종이가 있다. 모눈종이의 각 정사각형은 행과 열의 쌍으로 표현할 수 있다.

이 모눈종이 전체를 양의 정수의 소용돌이 모양으로 채울 것이다. 일단 숫자 1을 0행 0열에 쓴다. 그리고 나서 0행 1열에 숫자 2를 쓴다. 거기서 부터 소용돌이는 반시계 방향으로 시작된다. 다음 숫자는 다음과 같이 채우면 된다.

    -3 -2 -1  0  1  2  3
    --------------------
-3 |37 36 35 34 33 32 31
-2 |38 17 16 15 14 13 30
-1 |39 18  5  4  3 12 29
 0 |40 19  6  1  2 11 28
 1 |41 20  7  8  9 10 27
 2 |42 21 22 23 24 25 26
 3 |43 44 45 46 47 48 49

이 문제는 위와 같이 채운 것을 예쁘게 출력하면 된다. r1, c1, r2, c2가 입력으로 주어진다. r1, c1은 가장 왼쪽 위 칸이고, r2, c2는 가장 오른쪽 아래 칸이다.

예쁘게 출력한다는 것은 다음과 같이 출력하는 것이다.

 

  1. 출력은 r1행부터 r2행까지 차례대로 출력한다.
  2. 각 원소는 공백으로 구분한다.
  3. 모든 행은 같은 길이를 가져야 한다.
  4. 공백의 길이는 최소로 해야 한다.
  5. 모든 숫자의 길이(앞에 붙는 공백을 포함)는 같아야 한다.
  6. 만약 수의 길이가 가장 길이가 긴 수보다 작다면, 왼쪽에서부터 공백을 삽입해 길이를 맞춘다.

입력

 

첫째 줄에 네 정수 r1, c1, r2, c2가 주어진다.

 

출력

 

r2 - r1 + 1개의 줄에 소용돌이를 예쁘게 출력한다.

 

🚧  주의할 점


1) row와 column이 절대값이 5000보다 작다고 하니 최대로 나올수 있는 칸의 수는 10000*10000 1억 이므로 주어지는 시간 2초안에 계산이 가능하다.

 1억개 이므로 int배열로 충분하지만 전부 구하기 위해서 1억개의 int공간을 만든다면 메모리를 초과하게 되기 때문에 계산만하고 결과로 보여줄 부분만 map 배열에 넣는다.

 

🧐 핵심 로직 


1) 결과를 담을 배열을 선언한다.

 

2) 배열에 값을 채우기 위해 필요한 변수를 선언 후 범위 안에 들어온다면 값을 채운다.

    2 - a) 이때, while문은 배열의 모든 가장자리를 채웠다면 반복문을 벗어나도록 한다.

 

3) 위 혹은 아래로 이동했을 때 그 행에 들어가는 숫자가 1개씩 늘어가기 때문에 dnum을 통해 이를 표현한다.

 

4) 상용로그를 활용하여 최댓값의 자릿수를 구한 후 배열의 자릿수와 비교하며 공백을 추가하고 출력한다.

 

💻 최종 코드 (260 ms)


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

public class Main {

    static int r1, c1, r2, c2, maxNum;
    static int[][] map;
    static int[] dx = {0, -1, 0, 1};
    static int[] dy = {1, 0, -1, 0};
    public static void main(String[] args) throws Exception {

//        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedReader br = new BufferedReader(new FileReader("input.txt"));
        StringTokenizer st = new StringTokenizer(br.readLine());

        r1 = Integer.parseInt(st.nextToken());
        c1 = Integer.parseInt(st.nextToken());
        r2 = Integer.parseInt(st.nextToken());
        c2 = Integer.parseInt(st.nextToken());

        map = new int[r2 - r1 + 1][c2 - c1 + 1];

        fill();
        printResult();

        br.close();
    }

    private static void fill() {

        int x = 0, y = 0, dir = 0;
        int num = 1, dnum = 1, cnt = 0; // dnum은 위 혹은 아래로 이동했을 때 그 행에 들어가는 숫자가 1개씩 늘어가는걸 의미

        while (!isFinished()) {

            if (x >= r1 && x <= r2 && y >= c1 && y <= c2) {
                map[x - r1][y - c1] = num;
            }
            num++;
            cnt++;

            x = x + dx[dir];
            y = y + dy[dir];
            if (cnt == dnum) {
                cnt = 0;
                if (dir == 1 || dir == 3) dnum++;
                dir = (dir + 1) % 4;
            }
        }

        maxNum = num - 1;
    }

    private static void printResult() {

        int maxLen = (int) Math.log10(maxNum), len;

        for (int i = 0; i <= r2 - r1; i++) {
            for (int j = 0; j <= c2 - c1; j++) {
                len = maxLen - (int) Math.log10(map[i][j]);
                for (int k = 0; k < len; k++) {
                    System.out.print(" ");
                }
                System.out.print(map[i][j] + " ");
            }
            System.out.println();
        }
    }

    private static boolean isFinished() {
        return map[0][0] != 0 && map[r2 - r1][0] != 0 && map[0][c2 - c1] != 0 && map[r2 - r1][c2 - c1] != 0;
    }
}