본문 바로가기
백준

[백준 2447/Java] 별 찍기 - 10

by naahy 2023. 1. 19.

 

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



진짜 며칠에 걸려서 풀었다... 사실 이렇게까지 안 풀리면 그냥 풀이를 봤었는데, 지금까지 재귀 문제를 만족스럽게 풀었던 적이 한번도 없었어서 오기로 풀어봤다.
만족스러운 풀이는 아니었지만 결과를 내는 데엔 성공했는데 시간 초과남. for문을 중첩 사용했기 때문에 당연한 결과긴 했는데 다른 방식으론 어떻게 풀어야할지 모르겠어서 결국 다른 분 코드 확인함.


작은 사각형 각각을 한 덩어리로 나눠 풀 수도 있었다.
아무래도 별을 찍어야하니 무조건 잘게 나눠야 한다고 생각했는데, 재귀 함수를 사용해 각 덩어리를 파고들어갈 수가 있었음.
내가 일일이 for문을 돌며 별 한 개씩 안 파고들어도 된다는 소리

 

참고

https://st-lab.tistory.com/95

 

[백준] 2447번 : 별 찍기 - 10 - JAVA [자바]

 

st-lab.tistory.com


 

풀이

규칙

그림이 그려지는 규칙은 쉽게 찾을 수 있다. 입력으로 27이라는 숫자가 들어오면 위와 같이 27*27 사각형 가운데에 9*9 크기의 공백이 생기고, 그 주위를 9*9 사각형들이 둘러싼다. 그리고 각 9*9 사각형 안엔 똑같이 3*3 공백이 존재하고, 그 공백 주위를 3*3 사각형들이 둘러싸고 있는 형태다.

 

좌표 표시

위와 같이 좌표를 표시하면 27*27 사각형은 (0, 0)부터 그리면 되는 것을 알 수 있고, 9*9 사각형은 (0, 0), (9, 0), (18, 0), (0, 9), (18, 9), (0, 18), (9, 18), (18, 18) 위치에서 각각 그리면 되는 것을 알 수 있다.

 

풀이 1

더보기
  • 시간 초과
    • for문 중첩 사용 문제 有
  • 그림을 표현할 2차원 boolean 배열 생성
    • true인 인덱스는 공백으로 표현
  • 입력받은 수 N, 시작 좌표 (x, y)를 매개변수로 갖는 [ic]drawStars()[/ic] 메소드 작성
    • (x, y)부터 시작해서 (N/3)*(N/3) 크기의 공백을 표시
    • 가장 안쪽 for문 2개가 끝나면 사각형 가운데에 공백이 생김. 이후 해당 공백을 둘러싸는 N/3 크기의 사각형을 그리기 위해 [ic]drawStars()[/ic] 메소드가 또 호출됨.
    • b가 3*m만큼 커진 후 다시 안쪽 for문 2개가 반복됨.

 

a, b를 사용하는 이유는 공백을 둘러싸고 있는 사각형을 그리기 위함이다. 파란색 9*9 사각형을 그리려면 시작 좌표가 (9, 0)이어야 하기 때문.

 

코드

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

public class Main {
	
	static boolean[][] stars;	// true == blank
	
	public static void drawStar(int n, int x, int y) {
		int m = n / 3;	// 공백의 한 변의 크기
		
		if (n >= 3) {
			for (int a=x; a<=stars.length-n; a+=3*m) {
				for (int b=y; b<=stars.length-n; b+=3*m) {
					for (int i=a+m; i<a+m+m; i++) {
						for (int j=b+m; j<b+m+m; j++) {
							stars[i][j] = true;
						}
					}
					drawStar(m, a, b);
				}
			}
		}
	}

	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
		
		int n = Integer.parseInt(br.readLine());
		stars = new boolean[n][n];
		
		drawStar(n, 0, 0);
		
		for (boolean[] star : stars) {
			for (boolean s : star) {
				if (s)
					bw.write(" ");
				else
					bw.write("*");
			}
			bw.write("\n");
		}
		bw.close();
	}

}

풀이 2

  • 한 변의 크기 n, 시작 좌표 (x, y), 공백 여부를 매개변수로 받는 [ic]drawStar()[/ic] 함수
  • 공백 여부가 true인 경우 해당 공백 크기만큼 공백 출력
  • 공백 여부가 false이고 한 변의 크기가 1이 아닌 경우 그 크기가 1이 될 때까지 함수 재귀 호출
    • for문을 통해 좌표를 이동하며 해당 블록이 공백인지 아닌지 확인
    • 블록의 순서를 셀 [ic]count[/ic] 변수 생성 후, 5번째 블록은 공백 처리

 

 

코드

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

public class Main {
	
	static boolean[][] stars;	// true == blank
	
	public static void drawStar(int n, int x, int y, boolean blank) {
		if (blank) {
			for (int i = x; i < x + n; i++) {
				for (int j = y; j < y + n; j++) {
					stars[i][j] = true;
				}
			}
			return;
		}
		
		if (n == 1) {
			return;
		}
		
		/*
		 * n = 27인 경우 한 블록의 사이즈는 9
		 * n = 9인 경우 한 블록의 사이즈는 3
		 * n = 3인 경우 한 블록의 사이즈는 1
		 */
		int size = n / 3;
		int count = 0;
		for (int i = x; i < x + n; i += size) {
			for (int j = y; j < y + n; j += size) {
				count++;
				if (count == 5) {
					drawStar(size, i, j, true);
				} else {
					drawStar(size, i, j, false);
				}
			}
		}
	}

	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
		
		int n = Integer.parseInt(br.readLine());
		stars = new boolean[n][n];
		
		drawStar(n, 0, 0, false);
		
		for (boolean[] star : stars) {
			for (boolean s : star) {
				if (s)
					bw.write(" ");
				else
					bw.write("*");
			}
			bw.write("\n");
		}
		bw.close();
	}

}

댓글