Algorithm/Baekjoon(Java)

[백준/JAVA] 2447 : 별 찍기 - 10 ( 재귀 )

비망노트 2022. 8. 17. 23:30
문제

재귀적인 패턴으로 별을 찍어 보자. N이 3의 거듭제곱(3, 9, 27, ...)이라고 할 때, 크기 N의 패턴은 N×N 정사각형 모양이다.

크기 3의 패턴은 가운데에 공백이 있고, 가운데를 제외한 모든 칸에 별이 하나씩 있는 패턴이다.

***
* *
***

N이 3보다 클 경우, 크기 N의 패턴은 공백으로 채워진 가운데의 (N/3)×(N/3) 정사각형을 크기 N/3의 패턴으로 둘러싼 형태이다. 예를 들어 크기 27의 패턴은 예제 출력 1과 같다.

입력

첫째 줄에 N이 주어진다. N은 3의 거듭제곱이다. 즉 어떤 정수 k에 대해 N=3k이며, 이때 1 ≤ k < 8이다.

출력

첫째 줄부터 N번째 줄까지 별을 출력한다.

 

예제입력 예제출력
27

 

⭕ 풀이

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

public class Main{
    static String[][] arr;
    public static void main(String[] args)throws IOException{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        
        int input = Integer.parseInt(br.readLine());
        arr = new String[input][input];
        br.close();
        
        int cnt = 1;
        printStar(3,cnt);
        
        StringBuilder sb = new StringBuilder();
        for(int i=0;i<arr.length;i++){
            for(int j=0;j<arr[0].length;j++){
                sb.append(arr[i][j]);
            }
            sb.append("\n");
        }
        System.out.println(sb.toString());
    }
    
     public static void printStar(int x,int cnt){
        if(x<=arr.length){
            for(int i=0;i<arr.length;i++){
                for(int j=0;j<arr[0].length;j++){
                    if(((i/cnt)-1)%3==0&&((j/cnt)-1)%3==0){ 
                        arr[i][j]=" ";
                    }else{
                        if(arr[i][j]!=" "){
                            arr[i][j]="*";
                        }
                    }
                }
            }
            printStar(x*3,cnt*3);
        }else{
            return;
        }
    }
}

 

✅ 가뜩이나 아직 재귀함수도 제대로 이해하지 못한상태에서 재귀를 이용한 별찍기라니..

사실 어제 풀다가 포기하고 이전단계에 안풀려있던 문제로 하루 떔빵했다..

이런 모양까지 어제 만들어봤다가 중간중간 어떻게 구멍을 뚫어야할지

도저히 이리저리 살펴봐도 답이 나오지않았다..

 

 

 

 

이렇게 몇시간을 고민하다가 이번에도 이전문제 [백준/JAVA] 17478 : 재귀함수가 뭔가요? ( 재귀 )

에서 풀이해봤던 방식대로 기저조건을 0에 두는게 아니고 가장적은 값으로 호출하고

재귀호출할 때에 인자값을 늘려서 재귀호출하는 식으로 밑에서 위로 올라가는 방식으로 만들었다.

 

이방식으로 가장작은 패턴을 뚫고 그 다음 큰패턴으로 뚫고 그 다음 큰패턴으로 뚫어나가는 방식으로 작성하는게 목적이었다

 

for(int i=0;i<arr.length;i++){
    for(int j=0;j<arr[0].length;j++){
        if(i%3==cnt&&j%3==cnt){
            arr[i][j]=" ";
        }else{
            arr[i][j]="*";
        }
    }
}

 

우선 가장 적은 수 3을 넣어 실행시켜 이렇게

***

* *

***

모양을 가진 가장작은 3*3짜리 정사각형의 패턴을 모두 뚫어주었다.

 

 

 

 

for(int i=0;i<arr.length;i++){
    for(int j=0;j<arr[0].length;j++){
        if((i/3)%2==1&&(j/3)%2==1){
            arr[i][j]=" ";
        }
    }
}

 

 

이 조건으로 그 다음 큰 패턴의 9*9사각형의 구멍뚫기까지는 성공했으나

나누는 수가 고정이므로 이 다음 큰패턴으로 갔을때는 적용되지않았다.

 

그래도 어제의 막막했던 마음과 달리 오늘은 조금의 희망이 보인다

 

 

 

 

 

 

 

안보인다.. 그만하고싶어졌다

조건을 어떻게 주어야 구멍이 잘 뚫릴지 모르겠다..

 

이렇게 자포자기하는 심정으로 

문제풀마음은 사자리고 이런저런 조건식을 마구 대입해보며 별찍기놀이가 되어가고있었다

 

 

 

 

!?!??

if((i/(x/3))%(x/3)==1&&(j/(x/3))%(x/3)==1)

 

라는 조건을 넣었을때 드디어 27*27 사각형에 온전한 패턴이 찍혀나왔다.

해치웠나!?

 

 

 

 

 

81*81 로 늘려봤다. 

어림도없었다.

나무를 보지말고 숲을 보라고했다.

 

나무만 보고싶다.

 

그래도 아까부터 조금씩 발전하고있는듯한 느낌이 들었다.

 

사각형이 커질수록 뚫려야하는 범위도 커지니까

아무래도 나누는 조건에 들어가는 값이

증가될 수 있는 변수로 들어가야할것같다.

그리고 재귀호출할때 증가되는 변수도 넣어줘야할것같아서

매개변수를 하나 늘렸다.

 

 

for(int i=0;i<arr.length;i++){
    for(int j=0;j<arr[0].length;j++){
        if((i/cnt)%3==1&&(j/cnt)%3==1){ 
            arr[i][j]=" ";
        }else{
            if(arr[i][j]!=" "){
                arr[i][j]="*";
            }
        }
    }
}
printStar(x*3,cnt*3);

 

 

드디어 됐다!!

 

증가시키며 연산에 사용할 변수 cnt를 매개변수에 x와 같이 넣어주며

x 길이짜리 정사각형에 해당크기에 맞는 패턴을 뚫을 수 있게됐다.

 

해당조건에 부합한다면 구멍을 뚫고

만약 아니라면 *로 채우지만

if(arr[i][j]=" ")

이미 구멍이 뚫려있는 자리라면 그대로 놔두도록 작성했다

그렇지않으면 제일 마지막에 81이 x로 들어가서 

81짜리 정사각형에 해당하는 가운데 큰 구멍이있는 패턴이 아닌

자잘한 구멍들은 다 메꾸어버리기때문이다.

 

 

사실 st-lab님의 블로그에서 그동안 도저히 안풀릴것같을때 참고해왔기에 이번에도 참고를 하려했다.

하지만 조금씩 다듬어볼수록 희망이보이는것같고 조금만 더하면 될것같다.. 라는 생각때문에 

결국 혼자 풀긴했어도 빙 돌아온것같고 사실 시간도 오래걸는걸봐서는 이 방식이 적합한 코드는 아닌것같다..

 

그래도 간만에 재미있는 문제를 푼것같다.

사실 못풀었으면 재미없었을것같지만 어제부터해서 미뤄둔 숙제를 푼느낌이라 홀가분하다.

 

 

 

 

-출처

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