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 링크