ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [백준 18808] 스티커 붙이기
    C 프로그래밍/BOJ 2022. 9. 28. 23:18
    728x90

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

     

    18808번: 스티커 붙이기

    혜윤이는 최근에 다양한 대회를 참여하면서 노트북에 붙일 수 있는 스티커들을 많이 받았다. 스티커는 아래와 같이 사각 모눈종이 위에 인쇄되어 있으며, 스티커의 각 칸은 상하좌우로 모두 연

    www.acmicpc.net

    #include <cstdio>
    #include <vector>
    #include <algorithm>
    using namespace std;
    
    int N, M, K;
    int sticker[10 + 2][10 + 2];
    int laptop[40 + 2][40 + 2];
    int r_tmp[10 + 2][10 + 2];	// 회전 결과 저장용 배열 
    int r, c;	// 스왑때문에 전역으로 선언	// 이거 인자로 받아서 진행하면 안바뀜 ;
    
    
    int cnt_area()
    {
    	int cnt = 0;
    	for (int i = 0; i < N; i++) {
    		for (int j = 0; j < M; j++) {
    			//printf("%d ", laptop[i][j]);
    			if (laptop[i][j] == 1) cnt++;
    		}
    		//printf("\n");
    	}
    	return cnt;
    }
    
    
    
    void rotate_it()
    {
    	std::fill(&r_tmp[0][0], &r_tmp[0][0] + sizeof(r_tmp) / sizeof(int), 0);		//회전용 임시 배열 초기화 
    
    	for (int i = 0; i < r; i++) {
    		for (int j = 0; j < c; j++) {
    			r_tmp[j][r - i - 1] = sticker[i][j];
    		}
    	}
    	int tmp = r;
    	r = c;
    	c = tmp;
    
    	std::fill(&sticker[0][0], &sticker[0][0] + sizeof(sticker) / sizeof(int), 0);		// 스티커배열 초기화 
    	for (int i = 0; i < r; i++) {
    		for (int j = 0; j < c; j++) {
    			sticker[i][j] = r_tmp[i][j];
    		}
    	}
    }
    
    
    
    bool chk_n_fill(int x, int y)
    {
    	for (int i = 0; i < r; i++) {
    		for (int j = 0; j < c; j++) {
    			// 노트북에 자리 없으면 리턴 false
    			if (laptop[i + x][j + y] == 1 && sticker[i][j] == 1) return false;
    		}
    	} 
    
    	// 루프 다 돌았는데 리턴 안됐으면 스티커 붙일 수 있는 것임 
    	for (int i = 0; i < r; i++) {
    		for (int j = 0; j < c; j++) {
    			if (sticker[i][j]) laptop[i + x][j + y] = sticker[i][j];
    		}
    	}
    	return true;
    }
    
    
    
    void attach_it()
    {
    	int dir = 0;
    	while (dir < 4) {
    		if (dir != 0) rotate_it();
    		for (int i = 0; i <= N - r; i++) {
    			for (int j = 0; j <= M - c; j++) {
    				if (chk_n_fill(i, j)) return;
    			}
    		}
    		dir++;
    	}
    }
    
    
    void input()
    {
    	scanf("%d %d %d", &N, &M, &K);
    	for (int i = 0; i < K; i++) {	// K개의 스티커 붙인다
    		r = 0; c = 0;
    		scanf("%d %d", &r, &c);
    		std::fill(&sticker[0][0], &sticker[0][0] + sizeof(sticker) / sizeof(int), 0);
    		for (int j = 0; j < r; j++) {
    			for (int k = 0; k < c; k++) {
    				scanf("%d", &sticker[j][k]);
    			}
    		}
    		attach_it();
    	}
    }
    
    
    int main()
    {
    	input();
    	int ans = cnt_area();
    	printf("%d", ans);
    	return 0;
    }

    드디어 붙였다 스티커...ㅂㄷㅂㄷ 

    나의 머가리로는 스티커 붙이는 것도 어렵다고요... 

     

    // input( ) 함수

    원래는 3차원 배열에 받아서 하다가 헷갈려서 관뒀다. 다음에 복습할 때는 3차원 배열에 받아서 다시 짜봐야지.. 

    아무튼 스티커 배열을 입력받으면서 이것을 붙일 수 있는지 없는지 확인해주었기 때문에, 입력받기 전 마다 sticker 배열을 초기화 해줬다. 

     

     

    // attach_it( ) 함수

    회전을 4번(0, 90, 180, 270) 하면서 해당 스티커를 붙일 수 있는지 없는지 판단해야 하기 때문에 dir을 0~3까지만 돌려주었다. while루프를 빠져나오면 해당 스티커는 회전하여도 붙일 수 없는 것이기 때문에 버려야 한다. 

     

    여기서 중요한 점은 (노트북의 가로길이 - 스티커 가로길이) , (노트북 세로길이 - 스티커 세로길이) 만큼만 루프를 돌려주었다는 것이다. 스티커를 붙일 수 있는 공간(다시말해 스티커의 시작좌표)을 이렇게 한정해 두면 따로 영역체크를 하지 않아도 된다. 그리고 회전하여도 그때마다 r,c 값이 바뀌기 때문에 혼동되지 않는다. 

     

     

    // chk_n_fill( ) 함수

    attach_it 함수 내의 루프를 돌면서 해당 위치에 스티커를 붙일 수 있는지 없는지 확인하고, 있다면 스티커를 붙이는 함수이다. 

    스티커를 붙일 수 있는지 없는지 여부는 파악하기 쉽다. 노트북의 해당 영역에 이미 스티커가 붙여져 있는데(laptop[i + x][j + y] == 1), 스티커를 붙이려고 하면(sticker[i][j] == 1) 안된다. 이때는 더이상 탐색하지 않아도 되기 때문에 바로 false를 리턴하면서 함수를 빠져나온다. 

     

    반면 루프를 다 돌았는데도 함수를 빠져나가지 않았다면, 노트북의 해당 위치에 스티커를 붙일 수 있는 것이다. 이때 또 주의해야 할 점은, 스티커를 입력 받을 때 진짜 스티커가 있는 부분(1) 과 모눈종이(0)를 같이 입력받기 때문에, 노트북에 붙일 때는 스티커 + 모눈 종이 영역을 그냥 가져다 붙이는 것이 아니라 스티커 부분만 붙여야 한다. 따라서 " if(sticker[i][j]) " 이 조건이 추가되어야 한다. (경험을 통한 .. ^^.. 코멘트 .. ^^..)

     

     

    // rotate( ) 함수

    90도 씩 돌리는 함수이다. 돌리는건 쉬웠는데 r, c(스티커의 가로 세로 길이) 스왑하는 것 때문에 애좀먹었다(이렇게 스왑한 변수를 다른 함수에도 적용해야 되기 때문....). 생각하기 어려워요.. 이 rotate 함수 때문에 r과 c를 전역으로 선언하였다. 파라미터로 받아서 스왑하면 안바뀐다. 주소값 쓰면 될텐데 내 머가리로는 거기까지는 정말 한계치 이상이므로 그냥 전역변수로 선언하고, 데이터 입력 받을 때 마다 초기화 해줬다. ㅋㅋㅋㅋ

    이때, 스티커가 여러개 들어오므로 회전용 임시배열 r_tmp와 스티커배열 sticker를 초기화해주는 것을 잊지말자 !

     

     

     

    728x90

    'C 프로그래밍 > BOJ' 카테고리의 다른 글

    [백준 3967] 매직 스타  (0) 2022.09.29
    [백준 20055] 컨베이어 벨트 위의 로봇  (0) 2022.09.29
    [백준 3055] 탈출  (0) 2022.09.28
    [백준 11559] 뿌요뿌요  (0) 2022.09.28
    [백준 2589] 보물섬  (0) 2022.09.27

    댓글

Designed by Tistory.