[백준/Java] 1022 - [Gold III] 소용돌이 예쁘게 출력하기

2025. 8. 5. 17:33·코딩테스트/백준

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

 

문제를 해결하고 다른 사람들의 풀이를 보았는데 나의 코드만 유난히 장황한 것 같다

그래도 평소 약했던 구현 문제를 해결했으니 기록을 남겨본다

 

접근 방법

아래의 사진처럼 소용돌이가 좌표(0,0)의 숫자 1을 기준으로 한 라인씩 영역을 넓혀간다고 생각했다

이렇게 했을 때 각 라인별로 기준이 되는 숫자를 찾으려했고

1을 기준으로 왼쪽 위의 숫자들에서 다음과 같은 규칙을 발견했다

  • 라인 2
    • 숫자 1을 기준으로 다음 라인 왼쪽 위로 갈 때 +4
    • 숫자 5를 기준으로 같은 라인 오른쪽 아래로 갈 때 +4
  • 라인 3
    • 숫자 9를 기준으로 다음 라인 왼쪽 위로 갈 때 +8
    • 숫자 17을 기준으로 같은 라인 오른쪽 아래로 갈 때 +8
  • 라인 4
    • 숫자 25를 기준으로 다음 라인 왼쪽 위로 갈 때 +12
    • 숫자 37을 기준으로 같은 라인 오른쪽 아래로 갈 때 +12

해당 규칙을 통해 각 라인별 왼쪽 위에 있는 숫자를 기준으로 삼을 수 있다고 판단하였고

각 라인의 왼쪽 위 값을 구하는 코드는 다음과 같다

static int leftTop(int line){
        if(line == 0)
            return 1;
        return leftTop(line-1) + 4 + 8 * (line - 1);
    }

 

기준이 되는 숫자를 구했으니, 이제 각 좌표의 숫자를 구하는 방법만 생각해 보면 된다

먼저 y, x 좌표가 주어졌을 때 해당 좌표의 value를 구하는 방법을 생각하자

int leftTop = leftTop(line);
int leftBottom = leftTop + 2 * line;
int rightTop = leftTop - 2 * line;
int rightBottom = leftTop + 4 * line;
  1. 기준이 되는 leftTop을 기준으로 leftBottom, rightTop, rightBottom을 구한다
  2. 만약 |x|와 |y|의 값이 둘 다 line과 동일하다면 각 값에 맞추어 leftTop 혹은 leftBottome, rightTop, rightBottom을 반환한다
  3. y == line일 때 라인의 아래쪽에서 rightBottom을 기준으로 value를 구한다
  4. -y == line일 때 라인의 아래쪽에서 rightTop을 기준으로 value를 구한다
  5. x == line일 때 라인의 아래쪽에서 rightTop을 기준으로 value를 구한다
  6. -x == line일 때 라인의 아래쪽에서 leftTop을 기준으로 value를 구한다

해당 로직을 구현한 코드는 다음과 같다

    static int calcLeftLine(int leftTop, int line, int y){
        line = -line;
        while(line!=y){
            leftTop++;
            line++;
        }
        return leftTop;
    }
    static int calcRightLine(int rightTop, int line, int y){
        line = -line;
        while(line!=y){
            rightTop--;
            line++;
        }
        return rightTop;
    }
    static int calcTopLine(int rightTop, int line, int x){
        while(line!=x){
            rightTop++;
            line--;
        }
        return rightTop;
    }
    static int calcBottomLine(int rightBottom, int line, int x){
        while(line!=x){
            rightBottom--;
            line--;
        }
        return rightBottom;
    }

 

좌표에 있는 값을 반환하는 코드

static int calcPos(int y, int x){
        int line = Math.max(Math.abs(y), Math.abs(x));
        int leftTop = leftTop(line);
        int leftBottom = leftTop + 2 * line;
        int rightTop = leftTop - 2 * line;
        int rightBottom = leftTop + 4 * line;


        if(y == -line && x == -line)
            return leftTop;

        if(y==line && x == line)
            return rightBottom;

        if(y==line && x == -line)
            return leftBottom;

        if(y==-line && x == line)
            return rightTop;

        if(y == line)
            return calcBottomLine(rightBottom, line, x);
        if(-y == line)
            return calcTopLine(rightTop, line, x);
        if(x == line)
            return calcRightLine(rightTop, line, y);
        if(-x == line)
            return calcLeftLine(leftTop, line, y);

        return -1;
    }

 

이제 (y, x)를 기준으로 좌표를 구할 수 있으니

반복문을 통해 주어진 범위 내의 좌표를 돌아가며 값을 계산하면 된다

다만 제약조건에 다음과 같은 내용이 존재한다

 

해당 조건을 만족하기 위해 다음과 같은 절차를 거쳤다

  1. 좌표별 calcPos값을 문자열로 형변환한다 
  2. 숫자의 최대 길이를 최신화하고 문자열 배열에 값을 저장하며 반복문을 종료한다
  3. 문자열 배열에서 반복문을 다시 수행하며 최대 숫자 길이에 맞게 공백을 추가하며 StringBuilder에 값을 추가한다

전체 코드는 아래와 같다


해결 답안

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));
        StringTokenizer st = new StringTokenizer(br.readLine());
        StringBuilder sb = new StringBuilder();
        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 maxLength = 0;
        String[][] arr = new String[r2-r1+1][c2-c1+1];

        for(int i=r1; i<=r2; i++){
            for(int j=c1; j<=c2; j++){
                String s = String.valueOf(calcPos(i, j));
                maxLength = Math.max(s.length(), maxLength);
                arr[i-r1][j-c1] = s;
            }
        }

        for(int i=0; i<arr.length; i++){
            for(int j=0; j<arr[0].length; j++){
                String s = arr[i][j];
                for(int k=s.length(); k<maxLength; k++){
                    sb.append(' ');
                }
                sb.append(s).append(' ');
            }
            sb.append('\n');
        }
        System.out.println(sb);

        br.close();
    }

    static int calcPos(int y, int x){
        int line = Math.max(Math.abs(y), Math.abs(x));
        int leftTop = leftTop(line);
        int leftBottom = leftTop + 2 * line;
        int rightTop = leftTop - 2 * line;
        int rightBottom = leftTop + 4 * line;


        if(y == -line && x == -line)
            return leftTop;

        if(y==line && x == line)
            return rightBottom;

        if(y==line && x == -line)
            return leftBottom;

        if(y==-line && x == line)
            return rightTop;

        if(y == line)
            return calcBottomLine(rightBottom, line, x);
        if(-y == line)
            return calcTopLine(rightTop, line, x);
        if(x == line)
            return calcRightLine(rightTop, line, y);
        if(-x == line)
            return calcLeftLine(leftTop, line, y);

        return -1;
    }

    static int leftTop(int line){
        if(line == 0)
            return 1;
        return leftTop(line-1) + 4 + 8 * (line - 1);
    }

    static int calcLeftLine(int leftTop, int line, int y){
        line = -line;
        while(line!=y){
            leftTop++;
            line++;
        }
        return leftTop;
    }
    static int calcRightLine(int rightTop, int line, int y){
        line = -line;
        while(line!=y){
            rightTop--;
            line++;
        }
        return rightTop;
    }
    static int calcTopLine(int rightTop, int line, int x){
        while(line!=x){
            rightTop++;
            line--;
        }
        return rightTop;
    }
    static int calcBottomLine(int rightBottom, int line, int x){
        while(line!=x){
            rightBottom--;
            line--;
        }
        return rightBottom;
    }
}

'코딩테스트 > 백준' 카테고리의 다른 글

[백준/Java] 14502 - [Gold IV] 연구소  (0) 2025.06.17
[백준/Java] 17070 - [Gold V] 파이프 옮기기 1  (0) 2025.03.23
[백준/Java] 1620 - [Silver IV] 나는야 포켓몬 마스터 이다솜  (0) 2025.02.20
[백준/Java] 11660 - [Silver I] 구간 합 구하기 5  (0) 2025.02.14
[백준/Java] 13023 - [Gold V] ABCDE  (0) 2025.02.09
'코딩테스트/백준' 카테고리의 다른 글
  • [백준/Java] 14502 - [Gold IV] 연구소
  • [백준/Java] 17070 - [Gold V] 파이프 옮기기 1
  • [백준/Java] 1620 - [Silver IV] 나는야 포켓몬 마스터 이다솜
  • [백준/Java] 11660 - [Silver I] 구간 합 구하기 5
mint723dev
mint723dev
mint723dev 님의 블로그 입니다.
  • mint723dev
    mint723dev 님의 블로그
    mint723dev
  • 전체
    오늘
    어제
    • 분류 전체보기 (90)
      • Computer Science (16)
        • Computer Architecture (0)
        • Data Structure (2)
        • Database (4)
        • Network (4)
        • Operating System (6)
        • Software Engineering (0)
      • Java (6)
      • 자료 구조 (0)
      • 코딩테스트 (64)
        • LeetCode (1)
        • 프로그래머스 (29)
        • 백준 (34)
      • Spring (3)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    JVM
    DP
    오블완
    티스토리챌린지
    BFS
    탐욕법
    deque
    DFS
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
mint723dev
[백준/Java] 1022 - [Gold III] 소용돌이 예쁘게 출력하기
상단으로

티스토리툴바