반응형
Notice
Recent Posts
Recent Comments
«   2024/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 25 26 27 28 29 30
Archives
Today
Total
관리 메뉴

UP

[백준 12100 : PYTHON] 2048 (Easy) 본문

알고리즘/시뮬레이션

[백준 12100 : PYTHON] 2048 (Easy)

cijbest 2021. 6. 14. 13:57

문제 풀기 : 12100번

 

12100번: 2048 (Easy)

첫째 줄에 보드의 크기 N (1 ≤ N ≤ 20)이 주어진다. 둘째 줄부터 N개의 줄에는 게임판의 초기 상태가 주어진다. 0은 빈 칸을 나타내며, 이외의 값은 모두 블록을 나타낸다. 블록에 쓰여 있는 수는 2

www.acmicpc.net

 

문제

한 번의 이동은 보드 위에 있는 전체 블록을 상하좌우 네 방향 중 하나로 이동시킨다.

같은 값을 갖는 두 블록이 충돌하면 두 블록은 하나로 합쳐지게 된다.

한 번의 이동에서 이미 합쳐진 블록은 또 다른 블록과 다시 합쳐질 수 없다. (실제 게임에서는 이동을 한 번 할 때마다 블록이 추가되지만, 이 문제에서 블록이 추가되는 경우는 없다)

보드의 크기는 N×N 이다.

보드의 크기와 보드판의 블록 상태가 주어졌을 때, 최대 5번 이동해서 만들 수 있는 가장 큰 블록의 값을 구하라.

 

문제풀이

이 문제는 dfs, bfs 둘 다 사용해서 풀 수 있는 문제로 필자는 dfs로 접근해서 문제를 풀었다.

dfs 코드 작성은 쉽다. 상, 하, 좌, 우로 dfs를 돌리고 5번을 다 돌렸을 때 배열에서 가장 큰 값의 요소를 리턴해주면 4방향의 리턴값들 중 다시 최대값을 리턴하는 것이다.

가장 어려웠던 부분은 4방향으로 움직이는 함수들을 만드는 것이었다.

위로 움직였을 때의 상태를 예시로 들자면, 열순으로 두번째 행부터 탐색해주어야 한다. 이렇게 해주는 이유는 포인터를 사용하기 위함이다. 포인터는 가장 맨 앞쪽부터 위치해서 포인터가 가리키는 숫자들과 탐색되어지는 숫자들을 비교해 값을 변경하는 용도를 쓰여질 것이다. 이렇게 하는 이유는 경우의 수들을 보면 알 수 있다.

그럼 이제 경우의 수를 따져야 한다. 경우의 수는 3가지로 나뉠 수 있다.

  1. 포인터가 가리키는 수가 0일 때
  2. 포인터가 가리키는 수가 현재 위치의 수와 같을 때
  3. 포인터가 가리키는 수가 현재 위치의 수와 다를 때

첫 번째, 포인터가 가리키는 수가 0이라면 그 자리에 0이 아닌 수를 배치시켜야 하므로 현재 탐색한 수가 0이 아니면 포인터가 가리키는 곳에 탐색한 수를 넣는다. 현재 위치는 0으로 비워준다.

두 번째, 포인터가 가리키는 수가 현재 위치와 같다면 포인터의 수를 2배로 만들고 현재 위치는 0으로 만든 후에 포인터를 하나 증가시킨다. 포인터를 증가시키는 이유는 같은 수가 여러 개 연달아 있을 때 중복으로 더해질 수 있기 때문이다.

세 번째, 포인터가 가리키는 수가 현재 위치의 수와 다르면 포인터만 하나 증가시킨다.

 

전체코드

import sys
from copy import deepcopy
input = sys.stdin.readline

# INPUT
n = int(input())
board = [list(map(int, input().split())) for _ in range(n)]
answer = 0

# UP
def up(board):
    for j in range(n):
        pointer = 0
        for i in range(1, n):
            if board[i][j]:
                tmp = board[i][j]
                board[i][j] = 0
                # 포인터가 가리키는 수가 0일 때
                if board[pointer][j] == 0:
                    board[pointer][j] = tmp
                # 포인터가 가리키는 수와 현재 위치의 수가 같을 때
                elif board[pointer][j]  == tmp:
                    board[pointer][j] *= 2
                    pointer += 1
                # 포인터가 가리키는 수와 현재 위치의 수가 다를 때
                else:
                    pointer += 1
                    board[pointer][j] = tmp
    return board

# DOWN
def down(board):
    for j in range(n):
        pointer = n - 1
        for i in range(n - 2, -1, -1):
            if board[i][j]:
                tmp = board[i][j]
                board[i][j] = 0
                if board[pointer][j] == 0:
                    board[pointer][j] = tmp
                elif board[pointer][j]  == tmp:
                    board[pointer][j] *= 2
                    pointer -= 1
                else:
                    pointer -= 1
                    board[pointer][j] = tmp
    return board

# LEFT
def left(board):
    for i in range(n):
        pointer = 0
        for j in range(1, n):
            if board[i][j]:
                tmp = board[i][j]
                board[i][j] = 0
                if board[i][pointer] == 0:
                    board[i][pointer] = tmp
                elif board[i][pointer]  == tmp:
                    board[i][pointer] *= 2
                    pointer += 1
                else:
                    pointer += 1
                    board[i][pointer]= tmp
    return board

# RIGHT
def right(board):
    for i in range(n):
        pointer = n - 1
        for j in range(n - 2, -1, -1):
            if board[i][j]:
                tmp = board[i][j]
                board[i][j] = 0
                if board[i][pointer] == 0:
                    board[i][pointer] = tmp
                elif board[i][pointer]  == tmp:
                    board[i][pointer] *= 2
                    pointer -= 1
                else:
                    pointer -= 1
                    board[i][pointer] = tmp
    return board


# DFS
def dfs(board, cnt):
    if cnt == 5:
        # 2차원 배열 요소 중 가장 큰 값 반환
        return max(map(max, board))

    # 상, 하, 좌, 우로 움직여 리턴한 값들 중 가장 큰 값 반환
    # board를 꼭 deepcopy하여 함수를 거친 board값이 다음 함수에 들어가지 못하도록 해주어야 한다.
    return max(dfs(up(deepcopy(board)), cnt + 1), dfs(down(deepcopy(board)), cnt + 1), dfs(left(deepcopy(board)), cnt + 1), dfs(right(deepcopy(board)), cnt + 1))

print(dfs(board, 0))
반응형
Comments