Home 별 찍기 시리즈
Post
Cancel

별 찍기 시리즈

별 찍기 시리즈

별 찍기 시리즈

처음 풀었던 알고리즘? 프로그램? 문제라서 그런지 왠지 정이 가는 별찍기 문제다.
이중 반복문을 이해하는데 별 찍기만한 문제도 없다고 생각이 된다.
저 문제집에서 뒷 부분은 재귀 or 귀찮은 조건문 문제긴 하지만 나름 재밌다.

학원에서 가르치면서 딱 반복문 끝내면 꼭 별찍기 1~7을 풀게 했는데 이걸 잘하면 보통 잘하는 학생이고
힘들게 풀 수록 가르치는 것도 조금씩 힘들어지는 것 같다..

1번

1
2
3
4
5
*
**
***
****
*****
1
2
3
4
5
6
7
8
9
10
11
12
13
#include<stdio.h>
int main(){
    int A, i, j;
    scanf("%d", &A);
    for(i=1;i<=A;i++){
        for(j=1;j<=i;j++){
            printf("*");
        }
        printf("\n");
    }
    
    return 0;
}

이 i가 변화하는게 각 단계의 개수와 같다는 것을 파악하는 문제이다.

2번

1
2
3
4
5
    *
   **
  ***
 ****
*****
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
using namespace std;
vector <int> v(1000000);
int main()
{
    ios_base ::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
    int n;
    cin >> n;
    for(int i=1;i<=n;i++){
        for(int j=n;j>i;j--){
            cout<<" ";
        }
        for(int k=1;k<=i;k++){
            cout << "*";
        }
        cout << '\n';
    }
    
    return 0;
}

이제 빈칸이 생겼지만 사실 완전히 같은 문제이다.
아래로 갈 수록 작아지는 빈칸 삼각형과, 아래로 갈 수록 커지는 별 삼각형을 만들면 된다.

7번

3~6은 개수와 방향만 조금씩 바뀌기 때문에 2번을 이해했으면 풀어야 한다.

1
2
3
4
5
6
7
8
9
    *
   ***
  *****
 *******
*********
 *******
  *****
   ***
    *
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include<stdio.h>
#include<string.h>
int main(){
    int n, m, k, a, b, c = 0;
    scanf("%d", &n);
    for(int i=0;i<n;i++){
        for(int j=0;j<n-i-1;j++){
            printf(" ");
        }
        for(int k=0;k<2*i+1;k++){
            printf("*");
        }
        printf("\n");
    }
    for(int i=0;i<n-1;i++){
        for(int j=0;j<=i;j++){
            printf(" ");
        }
        for(int k=0;k<2*(n-i -1)-1;k++){
            printf("*");
        }
        printf("\n");
    }
}

사실 마름모도 같은 원리이긴 한데, 이건 위 삼각형과 아래 삼각형을 따로 만든다.

8~9번도 모양이 특이하지만 거의 같은 문제니까 스킵하자.

10번

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
***************************
* ** ** ** ** ** ** ** ** *
***************************
***   ******   ******   ***
* *   * ** *   * ** *   * *
***   ******   ******   ***
***************************
* ** ** ** ** ** ** ** ** *
***************************
*********         *********
* ** ** *         * ** ** *
*********         *********
***   ***         ***   ***
* *   * *         * *   * *
***   ***         ***   ***
*********         *********
* ** ** *         * ** ** *
*********         *********
***************************
* ** ** ** ** ** ** ** ** *
***************************
***   ******   ******   ***
* *   * ** *   * ** *   * *
***   ******   ******   ***
***************************
* ** ** ** ** ** ** ** ** *
***************************

프랙탈 문양을 별로 찍는 것이다.
규칙을 찾으면 큰 사각형에서 가로 1/3~2/3, 세로 1/3~2/3범위는 공백이다.
그러면 분할 정복으로 접근을 할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <iostream>
#include <vector>
#include <string>
#include <functional>
#include <queue>
#include <set>
#include <algorithm>
#include <math.h>
using namespace std;
int dx[4] = {-1, 0, 1, 0};
int dy[4] = {0, -1, 0, 1};
int main()
{
    ios_base ::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
    
    int a, b, c, d;
    long long n, m, t;
    cin >> n;
    int chk = 0;
    vector<vector<char>> v(n, vector<char>(n));

    function <void(int, int, int, int, int)> jae = [&](int x, int y, int size, int sx, int sy){
        if(x >= (sx + size/3) && x < (sx + size*2/3) && y >= (sy + size/3) && y < (sy + size*2/3)){
            chk = 1;
        }
        else{
            if(size > 3){
                sx = x / (size/3) * (size/3);
                sy = y / (size/3) * (size/3);
                jae(x, y, size/3, sx, sy);
            }
        }
    };

    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            chk = 0;
            jae(i,j,n,0,0);
            if(!chk)v[i][j]='*';
            else v[i][j] = ' ';
        }
    }

    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            cout << v[i][j];
        }cout << '\n';
    }
    return 0;
}

이렇게 구현을 할 수 있었다.

11번

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
                       *                        
                      * *                       
                     *****                      
                    *     *                     
                   * *   * *                    
                  ***** *****                   
                 *           *                  
                * *         * *                 
               *****       *****                
              *     *     *     *               
             * *   * *   * *   * *              
            ***** ***** ***** *****             
           *                       *            
          * *                     * *           
         *****                   *****          
        *     *                 *     *         
       * *   * *               * *   * *        
      ***** *****             ***** *****       
     *           *           *           *      
    * *         * *         * *         * *     
   *****       *****       *****       *****    
  *     *     *     *     *     *     *     *   
 * *   * *   * *   * *   * *   * *   * *   * *  
***** ***** ***** ***** ***** ***** ***** *****

아까 사각형이 삼각형으로 변한 듯한 느낌이다.
하지만 명확한 규칙이 안보여서, 분할 정복으로 접근하기에는 어려운 감이 있다.
다른 규칙을 찾았는데, 밑에 삼각형의 끝이 1쪽만 있으면 그 밑으로 삼각형이 생긴다.
만약 두 꼭짓점이 만나면 거기는 공백이다.

이 규칙에 착안해서 밑으로 내려갈 수 있으면 꼭짓점 밑 부분 배열에 1을 더하고
배열을 쭉 돌면서 1인 부분에서는 또 제일 작은 삼각형을 만들어준다.
만약 2라면 꼭짓점이 만난 부분이기에 삼각형을 만들면 안 된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include <iostream>
#include <vector>
#include <string>
#include <functional>
#include <queue>
#include <set>
#include <algorithm>
#include <math.h>
using namespace std;
int dx[4] = {-1, 0, 1, 0};
int dy[4] = {0, -1, 0, 1};
int main()
{
    ios_base ::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
    
    int a, b, c, d;
    long long n, m, t;
    cin >> n;
    int chk = 0;
    vector<vector<char>> v(n, vector<char>(2*n-1, 0));

    function <void(int, int)> jae = [&](int x, int y){
        v[x][y] = '*';
        v[x+1][y-1] = '*';
        v[x+1][y+1] = '*';
        v[x+2][y-2] = '*';
        v[x+2][y-1] = '*';
        v[x+2][y] = '*';
        v[x+2][y+1] = '*';
        v[x+2][y+2] = '*';
        if(x+3 < n){
            v[x+3][y-3]++;
            v[x+3][y+3]++;
        }
    };

    v[0][n-1] = 1;
    for(int i=0;i<n;i++){
        for(int j=0;j<2*n-1;j++){
            if(v[i][j]==1){
                jae(i,j);
            }
            else if(v[i][j]== '*'){
                continue;
            }
            else v[i][j] = ' ';
        }
    }

    for(int i=0;i<n;i++){
        for(int j=0;j<2*n-1;j++){
            cout << v[i][j];
        }cout << '\n';
    }
    return 0;
}

14번

12~13은 너무 쉬우니까
14번은 점수가 없는 문제인데 이유는 모르겠지만 n x n정사각형을 찍는다.

15~17도 평범하게 반복문으로 풀 수 있다.

18번

제일 구현이 귀찮은 모양의 별 찍기 문제였다.

3일 때는

1
2
3
4
5
6
7
      *
     * *
    *   *
   *******
  *  ***  *
 *    *    *
*************

4일 때는

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
*****************************
 *            *            *
  *          * *          *
   *        *   *        *
    *      *******      *
     *    *  ***  *    *
      *  *    *    *  *
       ***************
        *           *
         *         *
          *       *
           *     *
            *   *
             * *
              *

이렇게 짝수와 홀수일때 방향이 달라져서 조건문이 엄청 들어갔다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#include <iostream>
#include <vector>
#include <string>
#include <queue>
#include <stack>
#include <set>
#include <functional>
#include <algorithm>
#include <math.h>
#include <map>
using namespace std;
int main()
{
    ios_base ::sync_with_stdio(false); 
    cin.tie(NULL);
    cout.tie(NULL);
    
    int a, b, c, d;
    int n, m, k, t;
    int o_1, o_2;
    
    cin >> n;
    int s_n = n;

    vector<int> weight(11, 0);
    vector<int> height(11, 0);
    
    weight[1] = height[1] = 1;
    for(int i=2;i<=n;i++){
        weight[i] = 2*weight[i-1] + 3;
        height[i] = 2*height[i-1] + 1;
    }
    //2n+3개씩 늘어남.(가로) 1, 5, 13, 29
    //세로는 2n+1씩 늘어남. 1, 3, 7, 15
    vector<vector<char>> v(height[n], vector<char>(weight[n], ' '));
    int x = 0;
    int y = 0;

    if(n%2==1){
        x = height[n]-1;
    }

    n++;
    while(n--){
        if(n%2==0){ // 짝수 차례
            for(int i=0;i<weight[n];i++){
                v[x][y+i] = '*';
            }
            for(int i=0;i<height[n];i++){
                v[x+i][y+i] = '*';
            }
            for(int i=0;i<height[n];i++){
                v[x+i][y+weight[n] -1 - i] = '*';
            }
            x+=height[n-1];
        }
        else{
            for(int i=0;i<weight[n];i++){
                v[x][y+i] = '*';
            }
            for(int i=0;i<height[n];i++){
                v[x-i][y+i] = '*';
            }
            for(int i=0;i<height[n];i++){
                v[x-i][y+weight[n] -1 - i] = '*';
            }
            x-=height[n-1];
        }
        y += height[n-1]+1;
    }

    if(s_n%2==0){
        for(int i=0;i<height[s_n];i++){
            for(int j=0;j<weight[s_n]-i;j++){
                cout << v[i][j];
            }cout << '\n';
        }
    }
    else if(s_n%2==1){
        for(int i=0;i<height[s_n];i++){
            for(int j=0;j<weight[s_n]/2+1+i;j++){
                cout << v[i][j];
            }cout << '\n';
        }
    }

    return 0;
}

그냥 조건을 다 나눠줬다.

나머지 문제들도 적당히 구현을 해주면 된다. 특별한 아이디어는 없었다.
출력 결과인 프랙탈 모양들이 예뻐서 푸는 맛은 있지만 너무 귀찮았다.

This post is written by PRO.