baekjoon

백준 1022번 : 소용돌이 예쁘게 출력하기 [자바]

Meluu_ 2025. 2. 4. 18:19

🧫 문제 분석

✔️ 출처

소용돌이 예쁘게 출력하기 골드 3

 

📖 문제


좌표 (0,0) 에서 시작해서 

상하좌우로 이동한다.

 

이동 방향은

→ ↑ ← ↓ 이렇게 반시계방향이며

이동 거리는 1에서 시작해서

2번 방향을 전환하면 이동거리1씩 증가

 

 

이동 한 좌표를 갱신하면서 

현재 위치가 문제에서 주어진 r2,r1,c1,c2 박스 범위 안에 있는지 확인한다.

범위 안에 있다면 그 위치에 숫자를 넣어주면 된다. (숫자는 이동할때마다 1씩 증가)

 

문제는 r1,c1,r2,c2가 -5000 ~ 5000까지 범위인데

우리가 만드는 배열들은 음수 인덱스 표현이 안된다. 

이렇게 시작지점을 0,0으로 끌어당겨야한다.

 

arr[현재 위치r - r1] [현재 위치c - c1] 로 인덱스에 접근하면 

r1, r2가 0,0으로 맞춰져서 배열 안 범위로 들어갈 것이다. 

 

 

출력

출력은 String.format을 사용하여 %(max숫자길이 + 1)d 로 포맷만들고 출력하였다.

 

+1을 한 이유는 '각 원소는 공백으로 구분한다. ' 라는 조건때문이며,

최대 길이인 숫자도 한칸 띄우기 위함이다.

 

그럼 처음 출력된 것도 공백이 생기는데 

이는 따로 if문으로 조건 처리하면된다. ( 숫자길이 -1 로 출력하게끔)

 

 


🔅 문제 풀이

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

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        StringTokenizer st = new StringTokenizer(br.readLine());
        int r1 = Integer.parseInt(st.nextToken());
        int c1 = Integer.parseInt(st.nextToken());
        int r2 = Integer.parseInt(st.nextToken());
        int c2 = Integer.parseInt(st.nextToken());
        
        // 소용돌이 순서 오른쪽 - 위 - 왼쪽 - 아래
        int[] dx = {1,  0, -1, 0};
        int[] dy = {0, -1,  0, 1};

        // 소용돌이를 출력할 배열 생성
        int[][] map = new int[r2- r1 + 1][c2 - c1 + 1];
        // 현 위치
        int[] pos = {0, 0};
        int fullCheck = 0; // 다 채워졌는지 확인
        int n = 1; // 현재 소용돌이 번호

        // 0,0 부터 확인
        if (checkBoundary(r2, pos, r1, c2, c1)) {
            map[pos[0] - r1][pos[1] - c1] = n;
            fullCheck++;
        }

        int moveDistance = 1; // 이동 길이
        int maxLengthNum = 1; // 최댓 값

        // 배열에 모두 채워질때까지
        while (fullCheck < map.length * map[0].length) {
            for (int j = 0; j < 4; j++) {
                for (int k = 0; k < moveDistance; k++) {
                    pos[0] += dy[j];
                    pos[1] += dx[j];
                    n++;

                    if (checkBoundary(r2, pos, r1, c2, c1)) {
                        map[pos[0] - r1][pos[1] - c1] = n;
                        maxLengthNum =  Math.max(maxLengthNum, n);
                        fullCheck++;
                    }
                }
                // 2개의 방향당 이동 거리를 1씩 늘림
                if (j % 2 == 1) moveDistance++;
            }
        }

        // 제일 긴 수 길이 얻기
        int len = String.valueOf(maxLengthNum).length() + 1;

        // 출력
        for (int[] arr : map) {
            for (int i = 0; i < arr.length; i++) {
                bw.write(String.format("%" + (i == 0 ? len - 1 : len)  + "d",arr[i]));
            }
            bw.write("\n");
        }

        bw.flush();
        bw.close();
    }

    //r2 >= 현재 행 >= r1 && c2 >= 현재 열 >= c1
    private static boolean checkBoundary(int r2, int[] pos, int r1, int c2, int c1) {
        return r2 >= pos[0] && r1 <= pos[0] && c2 >= pos[1] && c1  <= pos[1];
    }
}

 

 

 

❗ 오답노트 / 필요한 지식

  1.  범위 문제는 항상 인덱스 처리가 문제다. 0,0으로 어떻게 맞출지 항상 생각하자.