import sys
def input():
    return sys.stdin.readline().rstrip()

def check(arr):
    if max(arr) - min(arr) <=K:
        return False
    return True
def push():
    min_value = min(arr[-1])
    for i in range(N):
        if arr[-1][i] == min_value:
            arr[-1][i] += 1
def roll(arr):
    row,col = 1,1
    new_N = N
    time = 0
    while True:
        new_temp = [[-1 for _ in range(new_N-col)] for _ in range(row+1)]

        for y in range(col,new_N):
            new_temp[-1][y-col] = arr[-1][y]

        for y in range(col):
            for x in range(len(arr)):
                new_temp[y][len(arr)-x-1] = arr[x][y]
        new_N = new_N-col
        if time%2:
            row += 1
            col += 1
        time += 1
        arr = [row[:] for row in new_temp]
        row_N = len(new_temp)
        if row_N*(col+1) >N:
            break
    return arr
def outOfbound(x,y,row,col):
    if 0<=x<row and 0<=y<col:
        return False
    return True
def blow():
    row = len(new_arr)
    col = len(new_arr[0])
    temp = [[0 for _ in range(col)] for _ in range(row)]
    for x in range(row):
        for y in range(col):
            if new_arr[x][y] == -1:continue
            for i in range(4):
                nx = x + dx[i]
                ny = y + dy[i]
                if outOfbound(nx,ny,row,col):continue
                if new_arr[nx][ny] == -1:continue
                if new_arr[x][y] - new_arr[nx][ny] >=5:
                    gap = (new_arr[x][y] - new_arr[nx][ny])//5
                    temp[x][y] -= gap
                    temp[nx][ny] += gap
    for x in range(row):
        for y in range(col):
            new_arr[x][y] += temp[x][y]
def flatting(maze):
    temp_arr = [[]]
    row = len(maze)
    col = len(maze[0])
    for y in range(col):
        for x in range(row-1,-1,-1):
            if maze[x][y]==-1:continue
            temp_arr[-1].append(maze[x][y])
    return temp_arr
def spread():
    spread_arr = flatting(new_arr)
    temp = [[-1 for _ in range(N//4)] for _ in range(4)]

    for x in range(4):
        if x%2:
            start_x = N//4*x
            y = 0
            while y<N//4:
                temp[x][y] = spread_arr[-1][start_x+y]
                y += 1
        else:
            y = N//4-1
            if x == 2:
                start_x = 0
            else:
                start_x = N//4*2
            while y>=0:
                temp[x][y] = spread_arr[-1][start_x]
                start_x += 1
                y -= 1
    return temp
                
    
N,K = map(int,input().split())

arr = [list(map(int,input().split()))]
dx = [-1,0,1,0]
dy = [0,-1,0,1]
turn = 0
while check(arr[-1]):
    push()
    new_arr = roll(arr)
    blow()
    new_arr = spread()
    blow()
    arr = flatting(new_arr)
    turn += 1
print(turn)

 

 

삼성 기출 문제들 중에서 푸는데 제일 오래걸렸던 문제였다.

 

패턴은 찾았는데, 그걸 코드로 옮기는데 힘들었다.

 

두가지 부분이 힘들었는데 돌돌 마는 부분이랑

 

그리고 마지막에 4부분을 나눠서 합치는 부분이다.

 

이 부분엗 대한 패턴을 찾고, 그걸 코드로 옮겨주면 되는 문제였다.

 

내가 찾은 패턴은

 

돌돌 마는 패턴에서는

 

처음에

 

row 1 col1

row2 col1

row2 col2

row3 col2

row3 col3

 

접혀진 부분의 크기가 이와 같음을 알 수 있다.

 

또한 이때 다음번의 영향은 그 전의 col만큼 이후것들은 제일 밑단에 감을 알 수 있고

 

원래 말려있던 부분들은 오른쪽으로 90도 회전을 함을 알 수 있다.

 

이런 방식으로 해서 구해주면 된다.

 

 

마지막으로 4부분으로 나눠서 합치는 부분은 예제 그림을 잘 보면 패턴을 찾을 수 있다.

 

위치가 어떻게 되어있던지

 

 

1 2 3 4 5 6 7 8 9 .... 4N

 

4N 이라는 길이의 array가 있으면

 

3N 3N-1 3N-2 .... 2N+1

N+1 N+2 .... 2N

N N-1 N-2 ....    1

3N+1 3N+2 .... 4N

 

처럼 접히는것을 알 수 있고, 이걸 구현해주면 된다.

 

이 외에는 이번 삼성기출에서 풀었던 것처럼 해주면 된다.

 

이 풀이 자체는 좀 난잡하게 푼 문제라서, python으로 푸시는 분들은

 

jh05013님의 풀이를 참조하시는걸 추천드립니다.

import sys
from collections import deque
def input():
    return sys.stdin.readline().rstrip()

def bfs(x,y,cnt):
    score = 0
    visited = [[False for _ in range(M)] for _ in range(N)]
    index_arr[x][y] = cnt
    visited[x][y] =True
    queue = deque()
    queue.append((x,y))
    stan = arr[x][y]
    while queue:
        x,y = queue.popleft()
        score += arr[x][y]

        for i in range(4):
            nx = x + dx[i]
            ny = y + dy[i]
            if 0<=nx<N and 0<=ny<M:
                if arr[nx][ny] == stan and not visited[nx][ny]:
                    visited[nx][ny] = True
                    index_arr[nx][ny] = cnt
                    queue.append((nx,ny))
    return score


def roll(direction):
    global dice
    if direction == 0:
        dice[0], dice[2], dice[3], dice[5] = dice[3], dice[0], dice[5], dice[2]
    elif direction == 1:
        dice[0], dice[1], dice[4], dice[5] = dice[1], dice[5], dice[0], dice[4]
    elif direction == 2:
        dice[0], dice[2], dice[3], dice[5] = dice[2], dice[5], dice[0], dice[3]
    else:
        dice[0] , dice[1] , dice[4], dice[5] = dice[4], dice[0], dice[5], dice[1]
def innerOfBound(x,y):
    if 0<=x<N and 0<=y<M:
        return True
    return False
def move(dire):
    x,y = dice_position
    nx = x + dx[dire]
    ny = y + dy[dire]
    if innerOfBound(nx,ny):
        return [(nx,ny),dire]
    dire = (dire+2)%4
    nx = x + dx[dire]
    ny = y + dy[dire]
    return [(nx,ny),dire]

def get_score(position):
    x,y = position
    return sum_list[index_arr[x][y]]
def curve(dire,position):
    x,y = position
    if dice[-1] > arr[x][y]:
        return (dire+1)%4
    elif dice[-1] < arr[x][y]:
        return (dire-1)%4
    else:
        return dire
N,M,K = map(int,input().split())

arr = [list(map(int,input().split())) for _ in range(N)]
dx = [0,1,0,-1]
dy = [1,0,-1,0]
index_arr = [[-1 for _ in range(M)] for _ in range(N)]
sum_list = []
cnt = 0
for x in range(N):
    for y in range(M):
        if index_arr[x][y] == -1:
            sum_list.append(bfs(x,y,cnt))
            cnt += 1

dice = [1,2,3,4,5,6]
dire = 0
# 동,남,서,북
# [4,2,1,6,5,3]
# [2,6,3,4,1,5]
# [3,2,6,1,5,4]
# [5,1,3,4,6,2]
dice_position = [0,0]
result = 0
while K>0:

    dice_position,dire = move(dire)
    roll(dire)
    result += get_score(dice_position)
    dire = curve(dire,dice_position)
    K -= 1
print(result)

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

 

14499번: 주사위 굴리기

첫째 줄에 지도의 세로 크기 N, 가로 크기 M (1 ≤ N, M ≤ 20), 주사위를 놓은 곳의 좌표 x, y(0 ≤ x ≤ N-1, 0 ≤ y ≤ M-1), 그리고 명령의 개수 K (1 ≤ K ≤ 1,000)가 주어진다. 둘째 줄부터 N개의 줄에 지

www.acmicpc.net

 

이 문제를 풀었던 사람이라면 쉽게 풀 수 있었던 문제인것 같다.

 

여기서 시간적으로 아끼자면, 단 1번의 bfs로 각 위치의 점수를 미리 구해두면 편하다.

 

그 외에는 문제에서 시키는 대로 회전하고 방향을 바꿔주면 되는 문제였다.

'알고리즘 > 백준' 카테고리의 다른 글

[BOJ/백준] 2240 자두나무  (0) 2021.12.04
[BOJ/백준] 23291 어항정리  (0) 2021.11.07
[BOJ/백준] 23290 마법사 상어와 복제  (0) 2021.10.26
[BOJ/백준] 23289 온풍기 안녕!  (0) 2021.10.25
[BOJ/백준] 1958 LCS 3  (0) 2021.09.28
import sys
def input():
    return sys.stdin.readline().rstrip()

def make_aqua():
    return [[[0 for _ in range(8)] for _ in range(4)] for _ in range(4)]
def outOfBound(x,y):
    if 0<=x<4 and 0<=y<4:
        return False
    return True

def move_fish(arr,T):
    new_aqua = make_aqua()
    for x in range(4):
        for y in range(4):
            for d in range(8):
                if arr[x][y][d]:
                    copy_d = d
                    for _ in range(8):
                        nx = x + dx[copy_d]
                        ny = y + dy[copy_d]
                        if outOfBound(nx,ny) or (nx,ny) == sharks or smells[nx][ny] >= T-2:
                            copy_d = (copy_d-1)%8
                        else:
                            new_aqua[nx][ny][copy_d] += arr[x][y][d]
                            break
                    else:
                        new_aqua[x][y][d] += arr[x][y][d]
    return new_aqua

def shark_swim(x,y,move,shark_dict,kill,visited):
    if len(move) == 3:
        shark_dict[move] = kill
        return
    else:
        for i in range(1,5):
            nx = x + shark_dx[i]
            ny = y + shark_dy[i]
            if outOfBound(nx,ny):continue
            if (nx,ny) not in visited:
                new_kill = sum(aqua[nx][ny])
                visited.add((nx,ny))
                shark_swim(nx,ny,move+str(i),shark_dict,kill + new_kill,visited)
                visited.remove((nx,ny))
            else:
                shark_swim(nx,ny,move+str(i),shark_dict,kill,visited)
def sharks_move(sharks,T):
    x,y = sharks
    shrks_dict = {}
    shark_swim(x,y,'',shrks_dict,0,set())
    move_sort = sorted(shrks_dict.keys(),key= lambda x : (-shrks_dict[x],x))
    for d in move_sort[0]:
        d = int(d)
        nx = x + shark_dx[d]
        ny = y + shark_dy[d]
        for i in range(8):
            if aqua[nx][ny][i]:
                aqua[nx][ny][i] = 0
                smells[nx][ny] = T
        x,y = nx,ny
    return x,y



N,S = map(int,input().split())
aqua = make_aqua()

for _ in range(N):
    x,y,d = map(int,input().split())
    aqua[x-1][y-1][d-1] += 1

dx = [0,-1,-1,-1,0,1,1,1]
dy = [-1,-1,0,1,1,1,0,-1]
shark_dx = [0,-1,0,1,0]
shark_dy = [0,0,-1,0,1]
smells = [[-float('inf') for _ in range(4)] for _ in range(4)]
sharks = tuple(map(lambda x: x-1,map(int,input().split())))
time = 0
while time<S:
    copy_aqua = [[col[:] for col in row] for row in aqua]
    aqua = move_fish(aqua,time)
    sharks = sharks_move(sharks,time)
    for x in range(4):
        for y in range(4):
            for d in range(8):
                aqua[x][y][d] += copy_aqua[x][y][d]

    time += 1

result = 0

for x in range(4):
    for y in range(4):
        result += sum(aqua[x][y])
print(result)

 

이 문제는 문제를 읽어보면 물고기의 개개로 움직이게 되면, 시간의 소모가 많이 되는것을 알 수 있다.

 

만약 물고기가 100만개를 일일히 전부 움직이고

 

최악의 경우를 생각해보면 1턴마다 100만*8의 이동이 되게 되고, 그것이 최대 100턴 지속되면 1억을 넘어가게 되서 시간초가가 날수도 있는 점을 생각해보면, 이 문제는 물고기의 위치와 방향에 따라 한꺼번에 움직이는 방식으로 해결해야함 을 알 수 있다.

 

먼저 4*4*8 크기의 aqua라는 수족관 배열을 만들어놓는다. 이 배열안에 입력으로 주어진 물고기의 위치와 방향에 맞게

 

넣어주면 된다.

 

이 문제도 삼성 기출 대부분이 그런것처럼 각 단계별이 있고, 그 단계에 맞게 시키는 것을 진행하면 된다.

 

그렇기 때문에 이 문제에서도 최대한 단계별에 맞게, 함수로 만들어서 진행을 했다.

 

1단계는 현재 수족관에 있는 물고기에게 복제 마법을 하는 것이다.

 

그렇다는 것은 현재 aqua에 있는 물고기 정보를 어디에 저장을 해야하기 때문에, 나는 copy_aqua라는 배열에,

 

현재 aqua의 물고기 정보를 저장해두었다.

 

여기서 deepcopy를 써도 되지만, 시간적으로 더 늦게 복사되기 때문에 list comprehension를 통해 복사를 해두었다.

 

2단계는 물고기가 움직이는 단계이다. 

 

물고기는 범위를 벗어나서도 안되고, 상어와 위치가 겹쳐서도 안되며, 물고기의 냄새가 있으면 안된다고 되어있다.

 

그리고 움직일 방향이 있을때까지 반시계 45도 방향으로 회전을 하며, 만약에 움직일 방향이 없으면 그 자리에 있는다.

 

라는 조건이 있다.

 

이 이동을 해결한 방법은 다음과 같다. 현재 물고기의 위치 x,y 와 방향 d가 있다하면,

 

우리는 문제에서 주어진 1~8의 이동방향이 숫자가 늘어남에 따라 시계방향으로 회전한다는 것을 알 수 있다.

 

그러면 우리는 반시계 45도 방향이라는 것은 주어진 이동방향 1~8을 각각 0~7로 변화시켰을때, 

 

(현재 이동방향-1)%8 을 하면, 반시계 45도 회전한 이동방향이 나옴을 알 수 있다.

 

그러면 우리는 총 8번의 반복을 하면서 범위를 벗어나거나, 상어가 존재하거나, 물고기 시체가 있을때에는

 

(이동방향 -1)%8을 해주면서 물고기를 계속 회전 시켜주면 된다는 것을 알 수 있다.

 

여기서 주의해야할 점은 원본의 이동방향은 그대로 냅두어야하기 때문에, copy_d라는 변수를 만들어 회전을 담당하는 변수를 새로 만들어줬다.

 

이렇게 해서 위의 3조건에 만족하지 않는 공간이 있을때에는 새 수족관에 더해주면 된다.

 

그리고 여기서도 for else문을 통해 8번의 방향전환동안, 물고기가 움직일 공간이 없을때에는,

 

현재 위치에 더해주는 로직을 해주었다.

 

여기서 중요한 물고기 시체와 관련된 사항은 밑에서 적도록 하겠다.

 

 

3번째 단계는 상어가 이동하는 단계이다.

 

상어는 상하좌우로 인접한 곳으로 이동을 하며, 이동하는 도중에 격자 범위를 벗어나는 이동은 무시한다고 되어있다.

 

이 상어 이동은 재귀를 통해 구현을 했으며, 재귀를 함에 있어서 주의해야할 점은

 

한번 물고기 먹은 곳을 당신 방문했을 때, 물고기를 먹는것을 중복해서 하지 않도록 방문 표시를 제대로 해주면 된다.

 

 

이렇게 상어의 모든 이동에 대해, 판별을 해준뒤 sort를 통해 물고기를 가장 많이 먹으면서,

 

이동방향이 사전순이 녀석으로 이동을 시켜준다.

 

여기서 물고기의 시체를 남겨두는 작업을 해야하는데, 이 물고기의 시체는 2턴뒤에 사라져야한다.

 

이 것을 따로 하나하나 초기화 하기에는 복잡하다고 생각되어,

 

4*4 크기의 smells라는 배열을 만들고, 거기에 물고기 시체가 생긴 턴을 적어두는 것으로 문제점을 해결했다.

 

 

smells[x][y] >= T- 2

 

특정위치의 냄새의 값이 현재턴에서 -2 한 값보다 크거나 같다는 것은 1턴전 혹은 2턴전에 물고기 시체가 되었다는 것을 의미하게 되고,

 

이렇게 표시하는 것만으로 자동적으로 2턴이 지난후에는 냄새가 사라지는것처럼 구현을 할 수 있다는 장점이 있다.

 

마지막으로 우리가 제일 첫번째에 해놓았던, copy_aqua를 원래 aqua에 더해주는 것으로

 

한 턴을 마무리 하면 된다.

 

문제에 주어진 턴을 모든 소모한뒤에 aqua에 남아있는 물고기의 수를 구해서 출력해주면 된다.

 

이 문제에서 주의해야했던 점은 몇가지가 있는데,

 

물고기의 시체가 2턴마다 사라지는 것을 어떻게 구현할 것인가와

 

상어의 이동방향은 어떻게 구현할것인가

 

그리고 물고기의 이동은 어떻게 구현할 것인가이다.

 

였다. 이 3부분에 대한 효율적으로 로직을 짜야했던 문제였다.

 

이 문제를 풀 때 1시간 30분이 걸렸는데, 30분동안 디버깅한게 tuple하고 list를 비교연산자로 비교해서 틀렸던 거였다..

 

list와 tuple은 타입이 다른 것을 다시 깨닫게 되었다.. 망할

 

 

 

def shark_swim(x,y,move,kill,visited):
    if len(move) == 3:
        return (kill,move)
    else:
        temp = (0,'000')
        for i in range(1,5):
            nx = x + shark_dx[i]
            ny = y + shark_dy[i]
            if outOfBound(nx,ny):continue
            if (nx,ny) not in visited:
                new_kill = sum(aqua[nx][ny])
                visited.add((nx,ny))
                temp = max(temp,shark_swim(nx,ny,move+str(i),kill + new_kill,visited))
                visited.remove((nx,ny))
            else:
                temp = max(temp,shark_swim(nx,ny,move+str(i),kill,visited))
        return temp

def sharks_move(sharks,T):
    x,y = sharks
    _,max_move = shark_swim(x,y,'',0,set())
    for d in max_move:
        d = int(d)
        nx = x + shark_dx[d]
        ny = y + shark_dy[d]
        for i in range(8):
            if aqua[nx][ny][i]:
                aqua[nx][ny][i] = 0
                smells[nx][ny] = T
        x,y = nx,ny
    return x,y
    
    
shark_dx = [0,0,1,0,-1]
shark_dy = [0,1,0,-1,0]

dict를 사용하지 않고, 재귀를 통해 max값을 되돌려주는 방식으로도 풀수 있다.

 

튜플로 max를 비교할수 있기 때문에 가능한 것이고, 이때는 앞에서는 1,2,3,4에 맞춰서 상좌우하를 만들었는데, 여기서는 반대로 더 높은숫자가 나올수 있도록 상좌우하를 4,3,2,1에 매핑을 시켜두었다.

'알고리즘 > 백준' 카테고리의 다른 글

[BOJ/백준] 23291 어항정리  (0) 2021.11.07
[BOJ/백준] 23288 주사위 굴리기 2  (0) 2021.10.27
[BOJ/백준] 23289 온풍기 안녕!  (0) 2021.10.25
[BOJ/백준] 1958 LCS 3  (0) 2021.09.28
[BOJ/백준] 2146 다리 만들기  (0) 2021.09.03
import sys
from collections import defaultdict,deque
def input():
    return sys.stdin.readline()
def outOfBound(x,y):
    if 0<=x<N and 0<=y<M:
        return False
    return True
def check(position):
    for x,y in position:
        if arr[x][y] <K:
            return True
    return False
def blocking(a,b):
    if block_air[a].get(b):
        return True
    return False
def air_dire(dir):
    swap_dir = [[],[3,4],[3,4],[1,2],[1,2]]
    return [[dir],[swap_dir[dir][0],dir],[swap_dir[dir][1],dir]]
def calcurate(conditioner):
    air = [[0 for _ in range(M)] for _ in range(N)]
    for x,y in conditioner:
        dir = conditioner[(x,y)]
        x = x + dx[dir]
        y = y + dy[dir]
        air[x][y] += 5
        visited = set()
        visited.add((x,y))
        queue = deque()
        queue.append((x,y,5))

        while queue:
            x,y,cnt = queue.popleft()

            for total_dir in air_dire(dir):
                cx,cy = x,y
                for i in total_dir:
                    nx = cx + dx[i]
                    ny = cy + dy[i]
                    if outOfBound(nx,ny):break
                    if blocking((cx,cy),(nx,ny)):break
                    cx,cy = nx,ny
                else:
                    if (cx,cy) not in visited:
                        visited.add((cx,cy))
                        air[cx][cy] = air[cx][cy] + cnt -1
                        if cnt >2:
                            queue.append((cx,cy,cnt-1))
    return air
def blow():
    temp = [[0 for _ in range(M)] for _ in range(N)]
    for x in range(N):
        for y in range(M):

            for i in range(1,5):
                nx = x + dx[i]
                ny = y + dy[i]
                if outOfBound(nx,ny):continue
                if blocking((x,y),(nx,ny)):continue
                if arr[x][y] >= arr[nx][ny] + 4:
                    gap = (arr[x][y] - arr[nx][ny])//4
                    temp[x][y] -= gap
                    temp[nx][ny] += gap

    for x in range(N):
        for y in range(M):
            arr[x][y] += temp[x][y]
            if arr[x][y]<0:
                arr[x][y] = 0
def down():
    for x in range(N):
        for y in range(M):
            if x == 0 or y == 0 or y == M-1 or x == N-1:
                if arr[x][y]:
                    arr[x][y] -= 1
N,M,K = map(int,input().split())

arr = [[0 for _ in range(M)] for _ in range(N)]
dx = [0,0,0,-1,1]
dy = [0,1,-1,0,0]
air_conditioner = {}
check_position = []
for x in range(N):
    temp = list(map(int,input().split()))
    for y in range(M):
        if temp[y] and temp[y]<5:
            air_conditioner[(x,y)] = temp[y]
        elif temp[y] == 5:
            check_position.append((x,y))

W = int(input())
block_air = defaultdict(dict)
for _ in range(W):
    x,y,c = map(int,input().split())
    x -= 1
    y -= 1
    if c == 0:
        block_air[(x,y)][(x-1,y)] = 1
        block_air[(x-1,y)][(x,y)] = 1
    else:
        block_air[(x,y)][(x,y+1)] = 1
        block_air[(x,y+1)][(x,y)] = 1
temperature_arr = calcurate(air_conditioner)

time = 0
while check(check_position) and time<=100:
    
    for x in range(N):
        for y in range(M):
            arr[x][y] += temperature_arr[x][y]
    blow()
    down()
    time += 1
print(time)

하반기 삼성 기출 문제라서 한번 풀어봤다.

 

삼성 기존 문제들이 그랬던 것처럼 시키는 대로 시뮬레이션을 돌면 되는 문제였다.

 

문제를 읽어보면 1턴에 차례대로 일정한 순서대로 한다.

 

1. 집에 있는 모든 온풍기에서 바람이 한번 나옴

2. 온도가 조절됨

3. 바깥의 온도가 1씩 감소

4. 1턴이 증가하고, 조사하는 모든 칸이 K도 이상이면 종료, 아니면 다시 처음부터 시작

 

총 4단계로 나뉘어져있고, 이걸 무한히 반복하면 된다.

 

그러면 이 문제를 풀기 위한 사전조건들을 먼저 구해주고, 각 단계별로 함수로 나누어서, 진행을 하면 된다.

 

그리고 이 문제를 풀면서 어려운 변수가 되는 것은 벽을 어떻게 판별을 헐것이냐 이다.

 

이 문제는 2차원 dict를 통해 해결를 했다. 문제에서 벽은 총 2종류로 가로로 세워진 벽, 세로로 세워진 벽이다.

 

그러면 이 벽을 어떻게 판별을 할것인가가 고민이었다. 이 문제는 a라는 위치에서 b라는 위치를 갈때 벽이 있느냐를 판별하면 되므로 2차원 dict를 통해 문제를 해결했다.

c가 0이라면, (x,y) 와 (x-1,y)를 키를 하는 dict를 만들어두고, 우리가 이동을 할때 해당 키가 존재하는지 유무를 통해, 벽이 존재하는지 안하는지를 판별할 수 있게 된다.

c가 1일때에도 동일하게 (x,y)와 (x,y+1)를 키로 하는 dict를 만들어주면 된다.

 

이렇게 먼저 사전작업을 해준뒤 위의 단계를 진행해주면 된다.

 

1번 로직인 집에 있는 모든 온풍기에서 바람이 1번 나옴은, 문제에서 주어진 것처럼 매턴 마다 일정한 값이, 일정한 칸에 더해지는 걸 알 수 있다.

 

그러므로, 먼저 clacurate 라는 함수를 통해, 모든 온풍기들이 바람이 불었을 때, 늘어나는 온도들을 미리 구해놓았다.

 

이렇게 1번 구해놓으면 N*M 을 반복하면서 원래 arr에 더해주면 끝이기 때문이다.

 

온풍기가 퍼지는 방향을 보면, 온풍기가, 동,서 방향으로 있다면, 동 서 방향으로 한칸씩 전진을 하며,

 

대각선 방향으로 진행될 때에는 먼저, 북이나 남 방향으로 퍼진뒤 동서 방향으로 진행을 하게 된다.

 

이 점을 이용하여, air_dire라는 함수를 통해, 온풍기가 진행하는 방향들을 먼저 구해주면 된다. 총 3가지 방향으로,

 

온풍기의 방향대로 나아가는 것과, 온풍기가 바라보는 방향의 90도 방향으로 먼저 꺾은뒤

 

온풍기가 바라보는 방향으로 진행을 하는 총 3가지의 방향을 한다.

 

위와 같이 준비를 한뒤에 bfs를 돌려주면 된다. 이 바람이 범위를 벗어나는지, 벽에 가로막혔는지를 판별을 하고, 

 

cnt가 2까지만 돌려주면 된다.

 

여기서 python의 for else 문을 사용할줄 알면 쉽게 트리거를 구분할 수 있다.

 

 

이렇게 우리는 calcurate를 통해, 우리는 온풍기가 켜졌을 때, 온도의 변화를 미리 구할 수 있게 되었다.

 

 

2번 로직은 인제 온도차를 통해, 온도가 조절되는 것을 구현을 해야한다. 이 부분도 비슷하게, N*M의 각 지점마다,

 

상하좌우를 탐색한 뒤, 벽으로 막혀있는지, 범위를 벗어나는지 먼저 판별을 하고 난뒤에,

 

인접한 위치의 온도가 현재 위치보다 온도가 낮으면, 그 온도의 gap을 4로 나눈 몫을 temp에 각각 마킹을 해준다.

 

온도가 높았던 곳은 - 온도가 낮았던 곳은 +를 해준다.

 

이렇게 모든 작업을 마친 뒤, 원본 배열에 더해주는 작업을 하고, 혹시 모르니, 음수는 0으로 바꿔주는 로직을 넣어줬다.

 

 

우리는 이렇게 크게 1,2번 로직을 완성했고, 인제 3,4번 로직을 구해놓으면 된다.

 

다음으로 3번 로직은 제일 외부의 온도가 1도씩 줄어든다고 했는데 사실 이건 구하기 쉬운 문제이다.

 

N*M 만큼 모든 점을 돌아다니면서 x가 0이거나 x가 N-1이거나 y가 0이거나 M-1일때에가 제일 외부인 걸 알 수 있다.

 

그리고 해당 위치의 온도가 1도이상 일때 온도를 1도씩 줄여주면 된다.

 

 

마지막으로 4번은 조사하는 부분들을 처음 입력이 들어왔을때, 따로 빼놓고,

 

이걸 반복문을 돌면서 한 곳의 온도가 K 미만이면, True 모든 곳의 온도가 K이상이면 False를 반환하는 check 함수를 만들어두었다.

 

그리고 모든 턴의 횟수가 101이 넘어가면 101로 출력해야하므로, time이 100이하일떄까지만 돌아가도록 while문을 작성해놓았다.

 

이 문제에서 크게 고민해야했던 부분은 3가지이다.

 

첫번째로, 1번 로직은 매번 반복되는 것이므로, 한번만 구해놓으면, 그 온도 변화량을 다시 구할 필요없이, 이용을 하면 된다.

 

두번째는 벽을 어떻게 구현을 할것인지 하는 것이다. 나는 이 문제를 풀때 두 튜플의 key값으로 하는 dict를 통해 만들어 뒀는데, 다른 방법들도 있을 것이다. 이 벽을 판별하는 것이 이 문제의 중요 포인트 중 하나였다.

 

그리고 마지막으로, 온풍기의 대각선 이동을 어떻게 구현을 하는것이냐였다.

 

온풍기의 진행방향에 벽이 세워져 있다하더라도, 온풍기의 90도 되는 방향에 벽이 없으면,

 

그 벽을 통해, 다음 칸으로 진행을 할수도 있었다. 그렇기 때문에, 온풍기의 대각선 이동방향을 어떻게 구현 할것인지가

 

꽤나 고민을 해야했던 부분이였다.

 

이 문제는 각각의 로직 별로, 함수를 만들어놓고, 그 함수 내에서 한가지 기능을 완료하는 식으로 해야,

 

어떤 부분에 에러가 발생했을때, 금방 알아차릴 수 있는 문제였다.

 

 

'알고리즘 > 백준' 카테고리의 다른 글

[BOJ/백준] 23288 주사위 굴리기 2  (0) 2021.10.27
[BOJ/백준] 23290 마법사 상어와 복제  (0) 2021.10.26
[BOJ/백준] 1958 LCS 3  (0) 2021.09.28
[BOJ/백준] 2146 다리 만들기  (0) 2021.09.03
[BOJ/백준] 1943 동전 분배  (0) 2021.09.03
def LCS(a,b,c):
    global X,Y,Z
    for i in range(1,X+1):
        for j in range(1,Y+1):
            for k in range(1,Z+1):
                if a[i-1] == b[j-1] and b[j-1] == c[k-1]:
                    LCS_array[i][j][k] = LCS_array[i-1][j-1][k-1] +1
                else:
                    LCS_array[i][j][k] = max(LCS_array[i][j][k], LCS_array[i-1][j][k], LCS_array[i][j-1][k], LCS_array[i][j][k-1])

a = input()
b = input()
c = input()
X = len(a)
Y = len(b)
Z = len(c)
LCS_array = [[[0 for _ in range(Z+1)] for _ in range(Y+1)] for _ in range(X+1)]


LCS(a,b,c)

print(LCS_array[X][Y][Z])

 

우리가 예전에 했던 LCS를 3차원으로 늘려주면 된다. 

 

1차원만 더 늘려주면 되는 문제라 쉽게 풀 수 있었던 문제였다.

import sys
from collections import deque
def input():
    return sys.stdin.readline().rstrip()

def island_bfs(x,y):
    queue = deque()
    queue.append((x,y))
    visited[x][y] = True
    island_check[x][y] = island_cnt
    temp = [(x,y)]
    while queue:
        x,y = queue.popleft()

        for i in range(4):
            nx = x + dx[i]
            ny = y + dy[i]
            if 0<=nx<N and 0<=ny<N:
                if not visited[nx][ny] and arr[nx][ny]:
                    visited[nx][ny] = True
                    island_check[nx][ny] = island_cnt
                    queue.append((nx,ny))
                    temp.append((nx,ny))
    island_list.append(temp)



N = int(input())

arr = [list(map(int,input().split())) for _ in range(N)]
visited = [[False for _ in range(N)] for _ in range(N)]
island_list = []
island_check = [[0 for _ in range(N)] for _ in range(N)]
island_cnt = 1
dx = [-1,0,1,0]
dy = [0,-1,0,1]
for x in range(N):
    for y in range(N):
        if arr[x][y] and not visited[x][y]:
            island_bfs(x,y)
            island_cnt += 1

result = float('inf')


for island_num in range(len(island_list)):
    queue = deque(island_list[island_num])

    visited = [[0 for _ in range(N)] for _ in range(N)]
    dis = 1
    while queue:
        q_size = len(queue)
        flag = False
        for _ in range(q_size):
            x,y = queue.popleft()

            for i in range(4):
                nx = x + dx[i]
                ny = y + dy[i]
                if 0<=nx<N and 0<=ny<N:
                    if island_check[nx][ny] != island_num+1 and not visited[nx][ny]:
                        visited[nx][ny] = dis
                        queue.append((nx,ny))
                        if island_check[nx][ny]:
                            result = min(result,dis-1)
                            flag = True
                            break
            if flag:
                break
        if flag:
            break
        dis += 1

print(result)

가장 첫 풀이는 직관적으로 푼 방식으로 각 섬들을 번호를 마킹해주고, 

 

한 섬의 있는 위치에서 다른 섬에 도착하는 최단 거리를 구해주는 방식이다.

 

 

import sys
from collections import deque
def input():
    return sys.stdin.readline().rstrip()

def island_bfs(x,y):
    queue = deque()
    queue.append((x,y))
    visited[x][y] = True
    island_check[x][y] = island_cnt
    temp = [(x,y)]
    while queue:
        x,y = queue.popleft()
        bridge_queue.append((x,y,island_cnt,0))
        for i in range(4):
            nx = x + dx[i]
            ny = y + dy[i]
            if 0<=nx<N and 0<=ny<N:
                if not visited[nx][ny] and arr[nx][ny]:
                    visited[nx][ny] = True
                    island_check[nx][ny] = island_cnt
                    queue.append((nx,ny))
                    temp.append((nx,ny))
    island_list.append(temp)

def bfs():
    global result
    while bridge_queue:
        x,y,island_num,dis = bridge_queue.popleft()

        for i in range(4):
            nx = x + dx[i]
            ny = y + dy[i]
            if 0<=nx<N and 0<=ny<N:
                if island_check[nx][ny] == island_num:
                    continue
                if result <= distance_list[nx][ny]:
                    return
                if not distance_list[nx][ny]:
                    distance_list[nx][ny] = dis + 1
                    island_check[nx][ny] = island_num
                    bridge_queue.append((nx,ny,island_num,dis+1))
                else:
                    if result > distance_list[nx][ny] + distance_list[x][y]:
                        result = distance_list[nx][ny] + distance_list[x][y]

N = int(input())

arr = [list(map(int,input().split())) for _ in range(N)]
visited = [[False for _ in range(N)] for _ in range(N)]
island_list = []
island_check = [[0 for _ in range(N)] for _ in range(N)]
island_cnt = 1
dx = [-1,0,1,0]
dy = [0,-1,0,1]
bridge_queue = deque()
for x in range(N):
    for y in range(N):
        if arr[x][y] and not visited[x][y]:
            island_bfs(x,y)
            island_cnt += 1

result = float('inf')

distance_list = [[0 for _ in range(N)] for _ in range(N)]

bfs()

                
print(result)

이 방식은 좀 더 빨리 풀 수 잇는 방식으로 위에서는 1섬마다 전부 초기화를 하고, 매번 구하는것에 반해

 

이 방식은 모든 섬에서 bfs를 동시에 시작하는 것이다.

 

만약 초기 상태의 점을 방문하게 되면, 해당 위치까지의 거리를 distance_list에 넣어주고, island_check에 해당 위치가 어느 섬에서 왔는지 마킹을 해준다.

 

그리고 만약 초기화 된 값이 아닌 이미 있는 값이라면, 비교를 해서 현재 위치의 distance_list[x][y] 와 distance_list[nx][ny]를 더한 값이 더 작으면 갱신을 해준다.

 

그리고 result가 distance_list[nx][ny]보다 작을 시에는 더 갱신할 경우의 수가 없으므로 함수를 종료해준다.

'알고리즘 > 백준' 카테고리의 다른 글

[BOJ/백준] 23289 온풍기 안녕!  (0) 2021.10.25
[BOJ/백준] 1958 LCS 3  (0) 2021.09.28
[BOJ/백준] 1943 동전 분배  (0) 2021.09.03
[BOJ/백준] 2143 두 배열의 합  (0) 2021.09.03
[BOJ/백준] 1823 수확  (0) 2021.09.03
import sys
from collections import defaultdict
def input():
    return sys.stdin.readline().rstrip()

max_coins = 50000
for _ in range(3):
    N = int(input())
    coins = defaultdict(int)
    dp = [0 for _ in range(max_coins+1)]
    dp[0] = 1
    total_sum = 0
    for _ in range(N):
        coin,cnts = map(int,input().split())
        for cur_coin in range(max_coins,coin-1,-1):
            if dp[cur_coin - coin]:
                for cnt in range(cnts):
                    next_coin = cur_coin + coin * cnt
                    if 0<=next_coin<=max_coins:
                        dp[next_coin] = 1
        total_sum += coin*cnts

    if total_sum%2 or not dp[total_sum//2]:
        print(0)
    else:
        print(1)

이 문제를 풀때 어려움을 많이 겪었다.

 

이 문제를 처음 푼 방식은 다음과 같다. dp는 동전을 만들수 있는 경우의 수이다.

 

먼저 dp[0]은 1로 초기화 해준다.

 

그리고 각 입력이 들어올때마다 dp를 max_coin에서 현재 들어온 동전인 coin 까지 반복문을 돌면서

 

cur_con - coin의 위치에 dp의 값이 존재하면, 만들 수 있는 경우의 수가 있으므로,

 

여기서 부터 다시 동전의 개수만큼 더해주면서 dp를 채워주면 된다.

 

이렇게 dp를 채워준 뒤에 전체 동전을 total_sum에 더해준다.

 

이렇게 한뒤에 만약 홀수 이거나 dp[total_sum//2]의 값이 존재하지 않으면 0을 출력한다.

 

 

import sys
from collections import defaultdict
def input():
    return sys.stdin.readline().rstrip()

def solution():
    N = int(input())
    coins = []
    total_coins = 0
    for _ in range(N):
        a,b = map(int,input().split())
        coins.append((a,b))
        total_coins += a*b
    if total_coins%2:
        return 0
    else:
        find_coin = total_coins//2
        dp = [0 for _ in range(find_coin+1)]
        dp[0] = 1
        coins.sort(key= lambda x : -x[1])
        acc_coins = 0
        for coin,cnts in coins:
            max_coin = coin*cnts
            for i in range(min(max(acc_coins,max_coin),find_coin),coin-1,-1):
                if dp[i-coin]:
                    for cnt in range(cnts):
                        next_coin = coin*cnt + i
                        if 0<=next_coin<=find_coin:
                            dp[next_coin] = 1
            if dp[find_coin]:
                return 1
            acc_coins += max_coin
        return 0
for _ in range(3):
    print(solution())

 

 

이 풀이는 좀 더 빠르대신 좀 더 복잡하다. 위에서는 고정된 최대값 50000에서부터 하나하나씩 찾는거라 하면,

 

이 풀이는 이 코인에서 가능한 최대값에서부터 하나씩 내려가는 것이다.

 

탐색이 가능한 최대 범위는 acc_coins 누적된 값 아니면 max_coin 중 더 큰 값에서부터 하나씩 내려가야한다.

 

우리는 dp[i - coin] coin 단 1개를 빼서 존재했을때부터 해당 동전이 가지는 개수를 갱신해주기 때문이다.

 

여기서 또 주의해야할 점은 위의 최대값이 find_coin을 넘어갈순 없다. 그러므로 둘중 min값 부터 시작해주면 된다.

'알고리즘 > 백준' 카테고리의 다른 글

[BOJ/백준] 1958 LCS 3  (0) 2021.09.28
[BOJ/백준] 2146 다리 만들기  (0) 2021.09.03
[BOJ/백준] 2143 두 배열의 합  (0) 2021.09.03
[BOJ/백준] 1823 수확  (0) 2021.09.03
[BOJ/백준] 1727 커플 만들기  (0) 2021.09.03
import sys
from collections import defaultdict
def input():
    return sys.stdin.readline().rstrip()

T = int(input())

N = int(input())
A_arr = [0] + list(map(int,input().split()))

M = int(input())
B_arr = [0] +list(map(int,input().split()))


for i in range(N):
    A_arr[i+1] += A_arr[i]

for j in range(M):
    B_arr[j+1] += B_arr[j]

A_nums = defaultdict(int)
B_nums = defaultdict(int)
for i in range(1,N+1):
    for j in range(i):
        A_nums[A_arr[i] - A_arr[j]] += 1

for i in range(1,M+1):
    for j in range(i):
        B_nums[B_arr[i] - B_arr[j]] += 1

result = 0
for num in A_nums:
    find_num = T -num
    if B_nums.get(find_num):
        result = result + A_nums[num] * B_nums[find_num]

print(result)

 

이 문제는 누적합을 이용해 풀었다. 이 문제는 다음과 같다. 두 배열이 주어지고,

 

두 배열의 원소들을 더해서 T가 나올 수 있는 경우의 수를 구하는 문제이다.

 

그래서 먼저 사전 작업을 해주었다.

 

각 배열들을 전부 누적합을 통해 특정 구간의 전체 합을 구하기 쉽게 만들어줬다.

 

이렇게 누적합을 미리 준비해주고,

 

j ->i 까지의 나올수 있는 모든 종류의 부분 합을 dict 에 저장을 해준다.

 

이렇게 사전 준비 작업을 했으면,

 

A_nums 라는 A 배열에서 나올 수 있는 모든 부분 배열의 합의 종류들의 key 값으로 탐색을 해준다.

 

T 에서 A에서 나올 수 있는 배열의 합을 뺀 값이 B에 존재 하면,

 

이 두 배열의 값들로 만들 수 있는 경우의 수는 A_nums[num] * B_nums[find_num]이 된다.

 

이 값들을 구해서 결과 값을 출력해주면 된다.

'알고리즘 > 백준' 카테고리의 다른 글

[BOJ/백준] 2146 다리 만들기  (0) 2021.09.03
[BOJ/백준] 1943 동전 분배  (0) 2021.09.03
[BOJ/백준] 1823 수확  (0) 2021.09.03
[BOJ/백준] 1727 커플 만들기  (0) 2021.09.03
[BOJ/백준] 1507 궁금한 민호  (0) 2021.09.03

+ Recent posts