ProblemSolve/항해99 코테스터디

99클럽 코테 스터디 19일차 TIL (챌린저): [백준][Java] 1022 소용돌이 예쁘게 출력하기 - 골드3

노루동산 2024. 11. 15. 17:07

 

문제 보기

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

 

 

풀이

이 문제의 핵심은 특정 좌표에 어떤 수가 들어올지 점화식을 구하는 것이다.

이 표를 뜯어보며 어떤 특징을 갖고 있는지 살펴보자.

 

1. 구역 찾기

우선 위와 같이 구역을 나눠 볼 수 있을 것 같다.

그럼 특정 좌표의 구역이 어디에 해당하는지 어떻게 구하면 좋을까?

x(c), y(r)의 값 중 절댓값이 더 큰 쪽을 고르면 되지 않을까?

int l = Math.max(Math.abs(r), Math.abs(c));

 

2. 구역 시작 수 구하기

구역을 찾았으니 이 구역의 시작 수부터 돌면서 숫자를 구해볼 수 있을 것 같다.

1은 무시하고 시작 수를 확인하자.

2, 10, 26, 50

1^2 + 1, 3^2 + 1, 5^2 + 1, 7^2 + 1... 홀수의 제곱 +1이라는 특징이 보인다.

int start = (2 * l - 1) * (2 * l - 1) + 1;

 

3. 구역 세분화 하기

아직 좌표에 대한 수를 찾을 점화식이 떠오르지 않았다.

숫자는 선형적으로 올라가지만 좌표의 값은 그렇지 않았다.

그래서 구역을 세분화했다.

if(-l <= r && r < l && c == l) {
  num = start + l - r - 1;
} else if(r == -l && -l <= c && c < l) {
  num = (start + (2 * l)) + l - c - 1;
} else if(-l < r && r <= l && c == -l) {
  num = (start + (2 * l) * 2) + l + r - 1;
} else if(r == l && -l < c && c <= l) {
  num = (start + (2 * l) * 3) + l + c - 1;
}
if(r == 0 && c == 0) {
  num = 1;
}

선형적으로 좌표가 증가 혹은 감소하도록 구역을 나눴다.

이제 좌표에 대한 점화식을 세울 수 있다!

r이 증가, 감소하거나 c가 증가, 감소하는 값에 맞춰 숫자가 증가하도록 식을 세우면 될 일이다.

난 처음부터 식을 생각하기보단 숫자를 대입해 보며 도출해 낸 것이다.

r, c, l 그리고 숫자가 어떤 연관성을 가지는지 직접 느껴봤으면 한다.

 

1은 예외 처리를 했다.

 

4. 공백

int max = Math.max(getNum(r1, c1), Math.max(getNum(r1, c2), Math.max(getNum(r2, c1), getNum(r2, c2))));

공백 처리는 최댓값의 길이에 비해 현재 숫자의 길이가 얼마나 짧은 지를 보면 된다.

모서리에 있는 숫자 중 하나가 최댓값일 것이기 때문에 전부 계산해서 비교해 봤다.

 

 

전체 코드

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.StringTokenizer;

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 max = Math.max(getNum(r1, c1), Math.max(getNum(r1, c2), Math.max(getNum(r2, c1), getNum(r2, c2))));
    int maxLength = String.valueOf(max).length();
    for(int r = r1; r <= r2; r++) {
      for(int c = c1; c <= c2; c++) {
        int num = getNum(r, c);

        int count = maxLength - String.valueOf(num).length();
        while(count-- > 0) {
          bw.write(" ");
        }
        bw.write(num + " ");
      }
      bw.newLine();
    }

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

  private static int getNum(int r, int c) {
    int l = Math.max(Math.abs(r), Math.abs(c));
    int start = (2 * l - 1) * (2 * l - 1) + 1;
    int num = 0;
    if(-l <= r && r < l && c == l) {
      num = start + l - r - 1;
    } else if(r == -l && -l <= c && c < l) {
      num = (start + (2 * l)) + l - c - 1;
    } else if(-l < r && r <= l && c == -l) {
      num = (start + (2 * l) * 2) + l + r - 1;
    } else if(r == l && -l < c && c <= l) {
      num = (start + (2 * l) * 3) + l + c - 1;
    }
    if(r == 0 && c == 0) {
      num = 1;
    }
    return num;
  }
}

 

 

GitHub 링크

https://github.com/MetroDefro/CodingTest_AutoSave/tree/main/%EB%B0%B1%EC%A4%80/Gold/1022.%E2%80%85%EC%86%8C%EC%9A%A9%EB%8F%8C%EC%9D%B4%E2%80%85%EC%98%88%EC%81%98%EA%B2%8C%E2%80%85%EC%B6%9C%EB%A0%A5%ED%95%98%EA%B8%B0

 

CodingTest_AutoSave/백준/Gold/1022. 소용돌이 예쁘게 출력하기 at main · MetroDefro/CodingTest_AutoSave

모든 코딩 테스트 자동 저장. Contribute to MetroDefro/CodingTest_AutoSave development by creating an account on GitHub.

github.com