ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [백준] 18808 스티커 붙이기
    Algorithm Study/Python 2021. 9. 28. 23:49

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

     

    18808번: 스티커 붙이기

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

    www.acmicpc.net

     

    풀이

    스티커가 들어갈 수 있는지 체크하고 들어가지 못하면 90도 회전시킨 후 다시 확인하는 단순한 구현이지만 세세한 부분을 체크해야하는 문제였다.

     

    ROW, COL, K = map(int, input().split())
    board = [[0 for _ in range(COL)] for _ in range(ROW)]
    stickers = []
    
    for i in range(K):
        r, c = map(int, input().split())
        temp = [list(map(int, input().split())) for _ in range(r)]
        stickers.append(temp)

    먼저 가로, 세로, 스티커의 갯수를 입력받고 전체 board를 설정한다.
    그리고 K개의 스티커를 입력 받아 stickers 리스트에 저장하였다.

     

    def check_sticker(sticker, y, x):
        r, c = len(sticker), len(sticker[0])
    
        for i in range(r):
            for j in range(c):
                if sticker[i][j] == 1 and board[y + i][x + j] == 1:
                    return False
    
        for i in range(r):
            for j in range(c):
                if sticker[i][j] == 1:
                    board[y + i][x + j] = 1
        return True

    스티커가 들어갈 수 있는지 체크하는 함수이다.
    board가 1일때 스티커도 1이면 붙일 수 없기 때문에 False를 반환하고 아닌 경우에는 다시 반복을 하면서
    board에 스티커를 붙였다는 의미로 1을 넣어줬다.

    특정 좌표부터 스티커의 크기까지 체크하기 때문에 입력 값으로 y, x를 받아야한다.

     

    def rotate_sticker(sticker):
        c, r = len(sticker), len(sticker[0])
    
        temp = [[0 for _ in range(c)] for _ in range(r)]
        for i in range(r):
            for j in range(c):
                temp[i][j] = sticker[c-1-j][i]
    
        return temp

    스티커를 붙일 수 없는 경우에 스티커를 90도 회전시키는 함수이다. 여기서 중요한 것이
    일반적인 N, N배열의 회전의 경우 row, col의 크기가 변하지 않기 때문에 문제가 없지만
    이 경우에는 R -> C, C -> R로 변하기 때문에 해당 부분을 잘 고려해야한다.

     

    for sticker in stickers:
        turn = 1
        while True:
            flag = False
            r, c = len(sticker), len(sticker[0])
            for y in range(ROW - (r - 1)):
                for x in range(COL - (c - 1)):
                    if check_sticker(sticker, y, x) is True:
                        flag = True
                        break
                if flag:
                    break
    
            if flag is False:
                if turn == 0:
                    break
                sticker = rotate_sticker(sticker)
                turn = (turn + 1) % 4
            elif flag:
                break

    위의 2가지 함수를 이용하여 스티커를 붙이고 같은 스티커가 2개 붙으면 안되기 때문에
    스티커가 붙은 경우에는 break를 해주었다.

    스티커를 3번까지 회전시키기 때문에 turn을 설정해서 4번 돌았을 경우 break하는 형식으로 구현했는데
    그냥 for문을 4번 반복시키는 것이 더 좋은 방법인 것 같다.

     

    answer = 0
    for i in range(ROW):
        for j in range(COL):
            if board[i][j] == 1:
                answer += 1
    
    print(answer)

    마지막에 전체 배열을 탐색하면서 스티커가 붙은 공간의 갯수를 세아리면 된다.

     

    전체 코드

    ROW, COL, K = map(int, input().split())
    board = [[0 for _ in range(COL)] for _ in range(ROW)]
    stickers = []
    
    for i in range(K):
        r, c = map(int, input().split())
        temp = [list(map(int, input().split())) for _ in range(r)]
        stickers.append(temp)
    
    def rotate_sticker(sticker):
        c, r = len(sticker), len(sticker[0])
    
        temp = [[0 for _ in range(c)] for _ in range(r)]
        for i in range(r):
            for j in range(c):
                temp[i][j] = sticker[c-1-j][i]
    
        return temp
    
    def check_sticker(sticker, y, x):
        r, c = len(sticker), len(sticker[0])
    
        for i in range(r):
            for j in range(c):
                if sticker[i][j] == 1 and board[y + i][x + j] == 1:
                    return False
    
        for i in range(r):
            for j in range(c):
                if sticker[i][j] == 1:
                    board[y + i][x + j] = 1
        return True
    
    for sticker in stickers:
        turn = 1
        while True:
            flag = False
            r, c = len(sticker), len(sticker[0])
            for y in range(ROW - (r - 1)):
                for x in range(COL - (c - 1)):
                    if check_sticker(sticker, y, x) is True:
                        flag = True
                        break
                if flag:
                    break
    
            if flag is False:
                if turn == 0:
                    break
                sticker = rotate_sticker(sticker)
                turn = (turn + 1) % 4
            elif flag:
                break
    answer = 0
    for i in range(ROW):
        for j in range(COL):
            if board[i][j] == 1:
                answer += 1
    
    print(answer)

    스티커를 4번 회전시켰을 때 정지하는 부분이 조금 깔끔하지 못하게 구현되어 있는 것 같다.

    이 문제의 경우 최대한 많은 스티커를 붙이는 것이 아니라 1번째 스티커부터 붙일 수 있는 첫번째 위치에 붙이기 때문에 단순 구현으로 해결할 수 있어서 복잡한 문제는 아니였지만 NxN의 배열이 아닌 경우는 ROW -> COL, COL -> ROW로 결과 배열의 크기가 변한다는 점을 신경써야하는 문제였다.

    'Algorithm Study > Python' 카테고리의 다른 글

    [SWEA] 원자 소멸 시뮬레이션  (0) 2021.10.08
    [SWEA] 보물상자 비밀번호  (0) 2021.10.05
    [백준] 16236번 아기 상어  (0) 2021.09.24
    [백준] 18428번 감시 피하기  (0) 2021.09.23
    [백준] 14889 스타트링크  (0) 2021.09.22

    댓글

From BlackHair