Notice
Recent Posts
Recent Comments
Today
Total
05-02 22:27
Archives
관리 메뉴

Jeongchul Kim

백준 삼성 코딩 기출 문제 - 2048 (Easy) python 본문

Algorithm

백준 삼성 코딩 기출 문제 - 2048 (Easy) python

김 정출 2019. 10. 16. 21:18

백준 삼성 코딩 기출 문제 - 2048 (Easy) python



출처 : BAEKJOON ONLINE JUDGE

2048 (Easy) (https://www.acmicpc.net/problem/12100)

문제 설명

2048 게임은 4×4 크기의 보드에서 같은 값을 갖는 두 블록이 충돌하면 합쳐집니다.

다음의 게임을 해보시면 이해가 갑니다ㅎㅎ 핸드폰 앱 게임으로도 많이 나와 있죠.

https://play2048.co


여기서는 NxN크기의 보드가 주어집니다. 이미 합쳐진 블록은 다른 블록과 다시 합쳐지지 않습니다. 실제 게임에서는 이동을 할 때마다 블록이 추가되지만, 이 문제에서는 추가되지는 않고 주어진 보드에서 최대 5번을 이동할 경우 가장 큰 블록 값을 구합니다.


문제 풀이

시뮬레이션을 해보는 문제입니다.

[1] 입력들을 받아들이고, queue를 생성합니다.

from collections import deque
n = int(input())
board = [list(map(int, input().split())) for _ in range(n)]
answer, q = 0, deque()


[2] 큰 구조로는  재귀함수를 쓰게 되고, move로 움직이고 그 이후를 재귀적으로 호출해 나가며 살펴봅니다.
- 최대 5번까지 움직였다면 멈추고 전체 배열의 최대 값을 반환합니다.
- 4방향으로 모두 움직여보고 재귀를 호출합니다.

 - 움직일 때마다 원본의 board를 기억하고 있어야 합니다.

def solve(count):
    global board, answer
    if count == 5: # 최대 5번까지 움직였다면
        for i in range(n):
            answer = max(answer, max(board[i])) # 가장 큰 값이 answer
        return
    b = [x[:] for x in board] # 방향을 바꾸기 전에 원래의 보드를 기억해야 한다.
   
    for k in range(4): # 4방향으로 움직인다.
        move(k) # 움직인다.
        solve(count+1) # 재귀적으로 호출한다.
        board = [x[:] for x in b]


[3] 우선 해당 row_index, column_index에 보드의 값을 가져옵니다. get() 보드에 0이 아닌 값이라면 큐에 넣고 0으로 처리합니다.

def get(i, j):
    if board[i][j]: # 0이 아닌 값이라면
        q.append(board[i][j]) # queue에 board의 값을 넣는다.
        board[i][j] = 0 # 처리가 된 빈 자리는 0으로 값 업데이트


[4] move() 움직이는 방향은 상/하/좌/우가 있습니다.


- 움직이려는 방향에 따라서 column_index 또는 row_index를 바깥 for문에 둡니다. 예를 들어 위, 아래로 움직이려면 블락들이 column_index를 고정하고 row_index들이 움직입니다. 따라서 for문 바깥에는 column이 안으로는 row가 돌면서 get()을 호출에 큐에 넣습니다.
- 반대로 좌, 우로 움직이려면 블락들이 row_index가 고정이 되고, column_index들이 움직여야겠죠. 따라서 for문 바깥에는 row이 안으로는 column으로 들어와 get을 호출에 큐에 넣습니다.


 - 움직였으면 합쳐야되는 merge()를 호출합니다.

 - 위로 움직이는 경우 : 모든  블락들이 합쳐졌다면 row index는 0에 위치합니다. 위로 움직이니 차례대로 아래쪽 row index가 증가하는 방향(+1)으로 블락을 합쳐나갑니다. 

 - 아래로 움직이는 경우 : 모든  블락들이 합쳐졌다면 row index는 n-1에 위치합니다. 위로 움직이니 차례대로 아래쪽 row index가 감소하는 방향(-1)으로 블락을 합쳐나갑니다.

 - 오른쪽으로 움직이는 경우 : 모든 블락들이 합쳐졌다면 column index는 n-1에 위치 합니다. 오른쪽으로 움직이므로, 차례대로 왼쪽 column index가 감소하는 방향으로(-1)으로 블락을 합쳐집니다.

 - 왼쪽으로 움직이는 경우 : 모든 블락들이 합쳐졌다면 column index는 0에 위치 합니다. 왼쪽으로 움직이므로, 차례대로 왼쪽 column index가 감소하는 방향으로(+1)으로 블락을 합쳐집니다.

def move(k):
    # board[i][j]
    if k == 0: # 위로 이동, 블락들이 위로 모두 이동하면 row index는 0
        for j in range(n):
            for i in range(n):
                get(i, j)
            merge(0, j, 1, 0) # row index 1씩 증가하면서 아래쪽 블락들을 합쳐감
    elif k == 1: # 아래로 이동, 블락들이 아래로 모두 이동하면 row index는 n-1
        for j in range(n):
            for i in range(n-1, -1, -1):
                get(i, j)
            merge(n-1, j, -1, 0) # row 인덱스 1씩 감소하면서 위쪽들을 합쳐감
    elif k == 2: # 오른쪽으로 이동, column index는 0
        for i in range(n):
            for j in range(n):
                get(i, j)
            merge(i, 0, 0, 1) # column 인덱스 증가 오른쪽으로 이동
    else: # 왼쪽으로 이동, column index는 n-1
        for i in range(n):
            for j in range(n-1, -1, -1):
                get(i, j)
            merge(i, n-1, 0, -1) # column 인덱스 감소 왼쪽으로 이동



[4] merge() 움직였으면 합쳐야겠죠.
- 큐에서 합치려는 블락들을 가져와 비교합니다.

 - 서로 값이 일치한다면 합쳐지면서 값은 2배로 증가됩니다.

 -  값이 일치하지 않거나, 0이라면 그대로 놓습니다.

def merge(i, j, di, dj): # row index, column index, y방향, x방향
    while q:
        x = q.popleft() # 움직이려는 블록 값을 가져온다. FIFO
        if not board[i][j]: # 0이라면 그대로 놓는다.
            board[i][j] = x
        elif board[i][j] == x: # 값이 일치한다면
            board[i][j] = x*2 # 합쳐지므로 2배로 증가
            i, j = i+di, j+dj
        else: # 값이 일치하지 않으면
            i, j = i+di, j+dj
            board[i][j] = x 



전체 코드

from collections import deque
n = int(input())
board = [list(map(int, input().split())) for _ in range(n)]
answer, q = 0, deque()

def get(i, j):
    if board[i][j]: # 0이 아닌 값이라면
        q.append(board[i][j]) # queue에 board의 값을 넣는다.
        board[i][j] = 0 # 처리가 된 빈 자리는 0으로 값 업데이트
       
def merge(i, j, di, dj): # row index, column index, y방향, x방향
    while q:
        x = q.popleft() # 움직이려는 블록 값을 가져온다. FIFO
        if not board[i][j]: # 0이라면 그대로 놓는다.
            board[i][j] = x
        elif board[i][j] == x: # 값이 일치한다면
            board[i][j] = x*2 # 합쳐지므로 2배로 증가
            i, j = i+di, j+dj
        else: # 값이 일치하지 않으면
            i, j = i+di, j+dj
            board[i][j] = x

def move(k):
    # board[i][j]
    if k == 0: # 위로 이동, 블락들이 위로 모두 이동하면 row index는 0
        for j in range(n):
            for i in range(n):
                get(i, j)
            merge(0, j, 1, 0) # row index 1씩 증가하면서 아래쪽 블락들을 합쳐감
    elif k == 1: # 아래로 이동, 블락들이 아래로 모두 이동하면 row index는 n-1
        for j in range(n):
            for i in range(n-1, -1, -1):
                get(i, j)
            merge(n-1, j, -1, 0) # row 인덱스 1씩 감소하면서 위쪽들을 합쳐감
    elif k == 2: # 오른쪽으로 이동, column index는 0
        for i in range(n):
            for j in range(n):
                get(i, j)
            merge(i, 0, 0, 1) # column 인덱스 증가 오른쪽으로 이동
    else: # 왼쪽으로 이동, column index는 n-1
        for i in range(n):
            for j in range(n-1, -1, -1):
                get(i, j)
            merge(i, n-1, 0, -1) # column 인덱스 감소 왼쪽으로 이동
           
def solve(count):
    global board, answer
    if count == 5: # 최대 5번까지 움직였다면
        for i in range(n):
            answer = max(answer, max(board[i])) # 가장 큰 값이 answer
        return
    b = [x[:] for x in board] # 방향을 바꾸기 전에 원래의 보드를 기억해야 한다.
   
    for k in range(4): # 4방향으로 움직인다.
        move(k) # 움직인다.
        solve(count+1) # 재귀적으로 호출한다.
        board = [x[:] for x in b]

solve(0)
print(answer)


Comments