from collections import deque

def bfs(x,y,color):
    global N
    stack = deque()
    stack.append((x,y))
    if color == 'B':
        chk = 2
    else:
        chk = 3
    visited[x][y] = chk
    while stack:
        x,y = stack.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] == color:
                    visited[nx][ny] = chk
                    stack.append((nx,ny))
    
def new_bfs(x,y,chk):
    global N
    stack = deque()
    stack.append((x,y))
    visited[x][y] = 0
    while stack:
        x,y = stack.popleft()
        for i in range(4):
            nx = x + dx[i]
            ny = y + dy[i]
            if 0 <=nx<N and 0<=ny<N:
                if visited[nx][ny] == chk:
                    visited[nx][ny] = 0
                    stack.append((nx,ny))

N = int(input())


arr = [list(input()) for _ in range(N)]
dx = [-1,1,0,0]
dy = [0,0,-1,1]
visited = [[0]*N for _ in range(N)]
cnt_a = 0
cnt_b = 0
for x in range(N):
    for y in range(N):
        if not visited[x][y]:
            bfs(x,y,arr[x][y])
            cnt_a += 1

for x in range(N):
    for y in range(N):
        if visited[x][y]:
            new_bfs(x,y,visited[x][y])
            cnt_b += 1

print(cnt_a,cnt_b)

2개의 BFS로 나누어, 3개의 색으로 구분할때와 2가지 색으로 구분할때 나눠서 탐색해주면 된다.

 

여기서 별다른 건 없고, visited 라는 리스트를 두번 만드는게 싫어서, 첫번째 bfs에서 visited에 체크하는 숫자를 청색 vs 녹색,빨간색을 서로 다르게 해주었고,

 

두번째 bfs에서는 원본 배열이 아닌 visited 함수를 통해 bfs를 돌려주었다.

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

[BOJ/백준] 2225 합분해  (0) 2021.02.16
[BOJ/백준] 3190 뱀  (0) 2021.02.16
[BOJ/백준] 14503 로봇 청소기  (0) 2021.02.16
[BOJ/백준] 16946 벽 부수고 이동하기 4  (0) 2021.02.16
[BOJ/백준] 1937 욕심쟁이 판다  (0) 2021.02.16
# 16946 벽 부수고 이동하기 4

# dfs를 해준다. 여기서 일반적인 dfs와 다른점은 방문표시 대신 해당 위치의 값을 들어온 index값으로 변형시켜준다.
def dfs(x,y,index):
    global index_dict,N,M

    stack = [(x,y)]
    cnt = 1
    arr[x][y] = index
    while stack:
        cx,cy = stack.pop()
        for i in range(4):
            nx = cx + dx[i]
            ny = cy + dy[i]
            if 0<=nx<N and 0<=ny<M:
                if not arr[nx][ny]:
                    stack.append((nx,ny))
                    arr[nx][ny] = index
                    cnt += 1
    # dfs를 전부 한뒤에 그 개수를 딕셔너리에 저장해준다.
    index_dict[index] = cnt




# dfs를 이용해서 쉽게 풀수 있었던 문제


N,M = map(int,input().split())

dx = [-1,1,0,0]
dy = [0,0,-1,1]
arr = [list(map(int,list(input()))) for _ in range(N)]
# 원본이 저장된 arr
result = [['0']*M for _ in range(N)]
# 결과값들을 저장해놓는 result 배열을 만들어둔다.

# 빈칸인 개수를 세주기 위해서 초기값을 -1로 해줬다. 왜냐하면 arr에는 1,0이 있으므로 겹쳐지지 않게 -1부터 시작해서 1씩 작아지게 해줬다.
# 그리고 해당 인덱스에 연결된 개수를 저장하기 위한 index_dict라는 딕셔너리를 미리 만들어줬다.
index = -1
index_dict = {}

# 빈칸의 개수를 세어주기 위한 dfs 공정
for x in range(N):
    for y in range(M):
        if not arr[x][y]:
            dfs(x,y,index)
            index -= 1

for x in range(N):
    for y in range(M):
        if arr[x][y] == 1:
            # 원본 배열에서 벽이 있을때, 그 벽 주변의 상황을 파악하고, 그 중에 1이 아닌 우리가 설정한 index값을 집합에 저장해준다.
            temp = set()
            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] != 1:
                        temp.add(arr[nx][ny])
            # 기본값은 1이고, temp에 저장된 index들을 반복문을 돌려 움직일수 있는 칸의 개수를 세준다.
            move_wall = 1
            for index in temp:
                move_wall += index_dict[index]
            # 그리고 result에 10으로 나눈 나머지를 string형태로 저장해준다.
            result[x][y] = str(move_wall%10)
# join을 이용해 출력해준다.
for row in result:
    print(''.join(row))

 이 문제는 union find 문제와 비슷하게 빈 위치의 그룹을 지어주면 된다.

 

최종 결과가 나올 result라는 2차원 배열을 '0'으로 초기화 해줬다. 왜냐하면, 나중에 출력을 할때, join을 쓰기 위해, 문자열 형태로 초기화 해줬다.

 

먼저 주어진 행렬의 빈칸들의 그룹의 정보를 저장해줄 index_dict을 만들어줬다. 여기서 key는 index 을 기준으로 해줬고, value는 그 그룹의 개수이다.

 

여기서 index 초기값을 -1을 해준 이유는 문제에서 0,1을 이미 쓰고 있어서, 겹치지 않기 위해 음수로 해줬다.

 

그러면 주어진 행렬에서 dfs 아니면 bfs를 해주면서, 빈칸들의 그룹들을 나눠 주는 작업을 해주고, 그 그룹의 크기와 index를 index_dict에 저장을 해주면서, 원본행렬에도 index를 대신 넣어준다.

 

 

벽 부수고 이동하기를 해주는 방법은 원본 행렬에서 1인 곳을 찾아서, 상하좌우에 있는 1이 아닌 값들을 집합에 저장을 해준다. 그리고 집합에 저장된 index들을 꺼내 전체 index_dict에 저장된 값들을 더해주면 된다. 그리고 원래 있던 벽이 무너지는 거니 1이 기본값이다.

 

그리고 결과값을 10으로 나눈 나머지를 문자열 형태로 저장해줬다.

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

[BOJ/백준] 10026 적록색약  (0) 2021.02.16
[BOJ/백준] 14503 로봇 청소기  (0) 2021.02.16
[BOJ/백준] 1937 욕심쟁이 판다  (0) 2021.02.16
[BOJ/백준] 9466 텀 프로젝트  (0) 2021.02.15
[BOJ/백준] 1759 암호 만들기  (0) 2021.02.15
# 13549 숨바꼭질 3
import collections
import sys

for _ in range(1000):
    start,end = map(int,input().split())
    dp = [-1]*100001
    dp[start] = 0
    dq = collections.deque()
    dq.append((start,0))
    if start == end:
        print(0)
    else:
        while True:
            x,time = dq.popleft()
            nx = 2*x
            while 0<nx <=100000:
                if dp[nx] == -1:
                    dp[nx] = time
                    dq.append((nx,time))
                nx = 2*nx
        
            if dp[end] != -1:
                break
            for nx in [x+1,x-1]:
                if 0<=nx<=100000:
                    if dp[nx] == -1:
                        dp[nx] = time + 1
                        dq.append((nx,time+1))
        
        print(dp[end])

첫 풀이 방식이다.  bfs처럼 풀었는데 단 조건은 두가지 경우를 나눠서 먼저했다. 먼저 해당위치에서 2배에 해당되는 것들만 먼저 방문을 해줬다. 왜냐하면 이동시간이 0초이기 때문이다. 그리고 난뒤 1초가 걸리는 +1,-1을 해주고 bfs 형식으로 풀어줬다.

start,end = map(int,input().split())
dp = [-1]*100001
dp[start] = 0
stack = [(start,0)]
if start == end:
    print(0)
else:
    while stack:
        new_stack = []
        for x,time in stack:
            for ind,nx in enumerate([2*x,x+1,x-1]):
                if 0<=nx<100001:
                    if dp[nx] == -1:
                        if ind == 0:
                            dp[nx] = time
                            new_stack.append((nx,time))
                        else:
                            dp[nx] = time +1
                            new_stack.append((nx,time+1))
        if dp[end] != -1:
            print(dp[end])
            break
        new_stack.sort(key=lambda x :(x[1]))
        stack = new_stack

ㅇ위와 똑같은 풀이이다. 하지만 여기서 달라진점은, 위에는 한개씩 진행한거에 반해 여기는 한단계씩 지금 내가 보유한 stack이 갈 수 있는 모든 곳을 다 넣어서, bfs를 돌린다는 것이다. 그리고 기준점은 시간이기때문에 시간을 기준으로 sort를 해주었다.

 

import heapq
start,end = map(int,input().split())
dp = [-1]*100001
dp[start] = 0

stack = []
heapq.heappush(stack,(0,start))
if start == end:
    print(0)
else:
    while stack:
        time,x = heapq.heappop(stack)
        for ind,nx in enumerate([2*x,x+1,x-1]):
            if 0<=nx<100001:
                if dp[nx] == -1:
                    if ind == 0:
                        dp[nx] = time
                        heapq.heappush(stack,(time,nx))
                    else:
                        dp[nx] = time +1
                        heapq.heappush(stack,(time+1,nx))
        if dp[end] != -1:
            print(dp[end])
            break

이 문제를 풀고보니 알고리즘 분류에 다익스트라가 있어서 그 방식으로 풀어본 코드이다. heapq를 이용한 방식이다.

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

[BOJ/백준] 1991 트리 순회  (0) 2021.02.15
[BOJ/백준] 11047 동전 0  (0) 2021.02.15
[BOJ/백준] 9020 골드바흐의 추측  (0) 2021.02.13
[BOJ/백준] 1107 리모컨  (0) 2021.02.13
[BOJ/백준] 15591 MooTube(Silver)  (0) 2021.02.13
# 1987 알파벳

def dfs(x,y,visited,cnt):
    global result,const,ccs
    for i in range(4):
        nx = x + dx[i]
        ny = y + dy[i]
        if 0 <= nx< R and 0<= ny<C and visited[ord(arr[nx][ny])-const]:
            visited[ord(arr[nx][ny])-const] = False
            dfs(nx,ny,visited,cnt+1)
            visited[ord(arr[nx][ny])-const] = True
    if cnt > result:
        result = cnt
ccs = 0
R,C = map(int,input().split())
dx = [-1,1,0,0]
dy = [0,0,-1,1]
arr = [list(input()) for _ in range(R)]
result = 1
visit = [True]*26
const = ord('A')
visit[ord(arr[0][0])-const] = False
dfs(0,0,visit,1)

print(result)

시간 초과의 늪에 빠졌던 문제이다. 기본적인 원리는 찾았으나, 문제를 해결하기 위한 방안을 찾기위해 노력했던 문제이다.

처음으로 풀었던 방식은 원래는 visited를 하나의 집합으로 해서 있는지 없는지 체크를 했다면, 알파벳에 해당되는 visited 리스트를 만들어주고 check 해주는 방식으로 풀었다.

 

 

# 1987 알파벳


R,C = map(int,input().split())

arr = [list(input()) for _ in range(R)]
check = [['']*C for _ in range(R)]

stack = [(0,0,1,arr[0][0])]
result = 0
dx = [-1,1,0,0]
dy = [0,0,1,-1]
while stack:
    x,y,cnt,total = stack.pop()
    if result < cnt:
        result = cnt
    if result == 26:
        break
    for i in range(4):
        nx = x + dx[i]
        ny = y + dy[i]
        if 0 <= nx < R and 0<= ny <C:
            if arr[nx][ny] not in total:
                temp = total + arr[nx][ny]
                if check[nx][ny] != temp:
                    check[nx][ny] = temp
                    stack.append((nx,ny,cnt+1,temp))
print(result)

시간이 빠른 방식은 다음과 같다. visited를 체크하는 것은 하나의 스트링을 통해 그 안에 있는지 없는지 확인하는 것이다.

여기까지는 동일하다. 하지만 결정적으로 다른것은 check라는 행렬을 통해 또 체크 하는 것이다.

지금까지 온 이동경로를 넣어놓는 check라는 행렬이다. 이 행렬에 존재하는 값과 같으면, 이미 그에 대해서 전부 탐색을 한 것이기 때문에 또 다시 탐색할 필요가 없다.

 

탐색한 경로들을 캐싱해놓은것과 같다. 서로다른 루트로 왔다 하더라도 다음위치에 똑같은 값으로 들어오는 거면 굳이 한번 더 검색을 할 필요가 없다.

 

이 방법은 dfs나 bfs 상관은 없으나 bfs를 할 시, collections의 deque를 쓰도록 하자. 안 그러면 시간 초과가 난다.

 

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

[BOJ/백준] 1107 리모컨  (0) 2021.02.13
[BOJ/백준] 15591 MooTube(Silver)  (0) 2021.02.13
[BOJ/백준] 1655 가운데로 말해요  (0) 2021.02.02
[BOJ/백준] 3197 백조의 호수  (0) 2021.02.01
[BOJ/백준] 1309 동물원  (0) 2021.01.31
# 3197번 Fail

import sys
def find(number):
    if parents[number] == number:
        return number
    parents[number] = find(parents[number])
    return parents[number]

def merge(root,child):
    parents[child] = root

def water_merge():
    while water:
        cx,cy = water.pop(0)
        flag = True
        for k in range(4):
            nx = cx + dx[k]
            ny = cy + dy[k]
            if 0<= nx <R and 0<= ny <C:
                if check_map[nx][ny] != -1 and check_map[nx][ny] != check_map[cx][cy]:
                    parentA = find(check_map[cx][cy])
                    parentB = find(check_map[nx][ny])
                    if parentA != parentB:
                        merge(parentA,parentB)
                        check_map[nx][ny] = parentA
                elif check_map[nx][ny] == -1 and flag:
                    melt_water.append((cx,cy))
                    flag = False


def water_melt():
    while melt_water:
        cx,cy = melt_water.pop(0)
        root = find(check_map[cx][cy])
        for k in range(4):
            nx = cx + dx[k]
            ny = cy + dy[k]
            if 0<= nx <R and 0<= ny <C:
                if check_map[nx][ny] == -1:
                    water.append((nx,ny))
                    check_map[nx][ny] = root        

R,C = map(int,input().split())

arr = [list(sys.stdin.readline()) for _ in range(R)]
check_map = [[-1]*C for _ in range(R)]
parents = [-1]*(R*C)
cnt = 0
dx = [-1,1,0,0]
dy = [0,0,-1,1]
swan = []
water = []
for x in range(R):
    for y in range(C):
        if arr[x][y] == '.' or arr[x][y] == 'L':
            water.append((x,y))
            parents[cnt] = cnt
            check_map[x][y] = cnt
            cnt += 1
            if arr[x][y] == 'L':
                swan.append((x,y))

swan1 = swan[0]
swan2 = swan[1]
time = 0
melt_water = []
while water:
    water_merge()
    if find(check_map[swan1[0]][swan1[1]]) == find(check_map[swan2[0]][swan2[1]]):
        result = time
        break
    water_melt()
    time += 1

            
print(result)

처음 시도했던 실패버전이다.

 

이 방법은 물을 union find로 한 묶음으로 한뒤, 탐색을 해주는 방식으로 했다. 그러나 이 방식의 문제점은 각 time에 대해 전부다 백조가 연결되어있는지 확인해야 하므로, 시간이 초과가 되었다. 

 

 

import sys
from collections import deque
import time
def isconnent_swan(start,end,standard_time):
    global R,C
    visited = [[True] * C for _ in range(R)]
    stack = deque()
    stack.append((start[0],start[1]))
    visited[start[0]][start[1]] = False
    while stack:
        x,y = stack.popleft()
        for i in range(4):
            nx = x + dx[i]
            ny = y + dy[i]
            if 0<= nx <R and 0<= ny <C:
                if melt_time[nx][ny] <= standard_time and visited[nx][ny]:
                    visited[nx][ny] = False
                    stack.append((nx,ny))
                    if nx == end[0] and ny == end[1]:
                        return True

    return False


def find_max_spend_time():
    global R,C
    while waters:
        x,y,time = waters.popleft()
        for i in range(4):
            nx = x + dx[i]
            ny = y + dy[i]
            if 0<= nx < R and 0<= ny < C:
                if melt_time[nx][ny] == -1:
                    melt_time[nx][ny] = time + 1
                    waters.append((nx,ny,time+1))
    return time
R,C = map(int,input().split())
origins = [list(sys.stdin.readline()) for _ in range(R)]
melt_time = [[-1]*C for _ in range(R)]
waters = deque()
swans = []
dx = [-1,1,0,0]
dy = [0,0,-1,1]
for x in range(R):
    for y in range(C):
        if origins[x][y] != 'X':
            waters.append((x,y,0))
            melt_time[x][y] = 0
            if origins[x][y] == 'L':
                swans.append((x,y))


max_time = find_max_spend_time()
min_time = 0
result = 0
while min_time <= max_time:
    mid_time = (min_time + max_time)//2
    if isconnent_swan(swans[0],swans[1],mid_time):
        answer = mid_time
        max_time = mid_time - 1
    else:
        min_time = mid_time + 1

print(answer)

두번째로 찾은 방법은 빙하가 녹는 시간을 미리 구해주는 것이다. BFS를 통해 각 빙하들이 녹는 시간들을 찾아주고, 이분탐색으로 시간을 줄여가면서 백조들끼리 연결되어있는지 구하는 것이다.

빙하가 녹는시간을 구해놓고, 기준시간보다 작거나 같을시에는 이동이 가능하다고 판별을 해주었다.

 

하지만 이 방법도 백조가 연결되어있는지 매번 BFS를 해야하므로, 실행시간이 오래걸리는 편이었다.

 

 

from collections import deque
import sys
R,C = map(int,input().split())

lake = [list(sys.stdin.readline()) for _ in range(R)]
waters = deque()
swans = []
water_chk = [[True] *C for _ in range(R)]
swan_chk = [[True] *C for _ in range(R)]
for x in range(R):
    for y in range(C):
        if lake[x][y] != 'X':
            waters.append((x,y))
            water_chk[x][y] = False
            if lake[x][y] == 'L':
                swans.append((x,y))
                lake[x][y] = '.'
start_swan,end_swan = swans
swans = deque()
swans.append(start_swan)
swan_chk[start_swan[0]][start_swan[1]] = False
times = 0
new_water = deque()
new_swans = deque()
dx = [-1,1,0,0]
dy = [0,0,-1,1]
while True:
    while waters:
        x,y = waters.popleft()
        lake[x][y] = '.'
        for i in range(4):
            nx = x + dx[i]
            ny = y + dy[i]
            if 0<= nx < R and 0<= ny <C:
                if lake[nx][ny] == 'X' and water_chk[nx][ny]:
                    new_water.append((nx,ny))
                    water_chk[nx][ny] = False
    while swans:
        x,y = swans.popleft()
        for i in range(4):
            nx = x + dx[i]
            ny = y + dy[i]
            if 0<=nx <R and 0<=ny<C:
                if swan_chk[nx][ny]:
                    if lake[nx][ny] == '.':
                        swans.append((nx,ny))
                    elif lake[nx][ny] == 'X':
                        new_swans.append((nx,ny))
                    swan_chk[nx][ny] = False

    if not swan_chk[end_swan[0]][end_swan[1]]:
        answer = times
        break
    waters = new_water
    swans = new_swans
    new_swans = deque()
    new_water = deque()
    times += 1

print(answer)

마지막 방식은 deque를 4개를 써서, 매번 bfs를 처음부터 하지 않아도, 되는 방식으로 해주었다.

 

water : 현재가 물인 상태인 것들이 모아져있는 deque

new_water : 다음 시간에 녹아질 예정인 빙하들의 deque

swan : 현재 시간에 swan이 돌아다닐수 있는 deque

new_swan : 다음 시간에 swan이 움직일수 있는 deque

 

이렇게 기능적으로 나눈뒤에,

 

먼저 water에서 다음에 녹을 water를 찾아준다. 이때 new_water에 들어가는 것은 호수에 빙하인것과 water_chk 한번도 방문하지 않은 곳이여야 한다.

그리고 여기서 처음 water를 pop할때 lake[x][y]를 . 를 입력해주는 것은 이전 time에 우리가 찾아놓은 new_water가 녹았기 때문에, 이때 값을 변경시켜주는 것이다.

 

이렇게 한뒤에, swan를 bfs를 돌리면서 물인곳은 계속 swan에 추가해서 bfs를 해주고, 만약 빙하인곳은 다음번에 들릴곳이기 때문에 new_swan에 넣어준다.

그리고 빙하와 물 상관없이 swan 방문을 check해준다.

 

이렇게 작업을 한뒤에, 우리가 찾는 반대편 swan에 도착했는지 확인을 해주고, 그때의 시간을 출력해주면 된다.

 

도착하지 않았으면, new_water를 water에 넣어주고, new_swan을 swan에 넣어준뒤 초기화를 시켜준다

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

[BOJ/백준] 1987 알파벳  (0) 2021.02.03
[BOJ/백준] 1655 가운데로 말해요  (0) 2021.02.02
[BOJ/백준] 1309 동물원  (0) 2021.01.31
[BOJ/백준] 11403 경로찾기  (0) 2021.01.30
[BOJ/백준] 9251 LCS  (0) 2021.01.29
# 11403 경로 찾기



N = int(input())
arr = [list(map(int,input().split())) for _ in range(N)]
for k in range(N):
    for x in range(N):
        for y in range(N):
            if arr[x][k] + arr[k][y] == 2:
                arr[x][y] = 1

for i in range(N):
    print(*arr[i])

풀고보니 플로이드 와샬 문제였다.

 

중간 경로를 통해서 두개가 연결이 되는 경우 arr를 갱신해주는 방식으로 했다.

 

이 방식 말고도 BFS,DFS를 통해 node들을 탐색해서 푸는 방식도 있다.

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

[BOJ/백준] 3197 백조의 호수  (0) 2021.02.01
[BOJ/백준] 1309 동물원  (0) 2021.01.31
[BOJ/백준] 9251 LCS  (0) 2021.01.29
[BOJ/백준] 14499 주사위 굴리기  (0) 2021.01.29
[BOJ/백준] 9633 N-queen  (0) 2021.01.28
# 12851 숨바꼭질

N,M = map(int,input().split())
dp = [-1]*100001
if M != N:
    stack = [(N,0,'')]
    flag = False
    result = float('inf')
    dire = ['M','P','T']
    total = set()
    visited = set()
    while stack:
        X,time,how = stack.pop(0)
        if time > result:
            break
        temp =  [X-1,X+1,X*2]
        for ind,k in enumerate(temp):
            if 0<=k<=100000 and time+1<=result:
                if dp[k] == -1 or dp[k] == time+1:
                    dp[k] = time+1
                    stack.append((k,time+1,how+dire[ind]))
                    if k == M:
                        result = time+1
                        total.add(how+dire[ind])

        
    print(result)
    print(len(total))
else:
    print(0)
    print(1)

처음에는 단순히 BFS처럼 풀어주었다.  결과값인 result를 큰 수로 설정해놓고, BFS를 하면, 최초로 변하는 값이 제일 작은 값이 되고, 출력되어야하는 값이 되니, result값보다 작은 time일때만 들어오게 설정해주었다. 그리고, 이 문제에서 처음에 틀렸던 이유 중 하나가, 같은 시간대에 정답에 올 수 있는 경우의 수가 많았다. 그래서 방문표시를 해주는 dp를 최초 방문이거나 아니면 time+1과 같을때, 같은시간대일때만 올 수 있도록 해줬다. 

 또한 전체적인 방법의 수를 찾기 위해, 이동방향을 저장해주는 로직을 추가해줬었다. 그래서 목표값 M에 도착을 하면, total에 추가를 해줘서, 전체 방법의 가지수를 찾아냈다.

 

하지만 이 방식의 문제점은, 시간이 오래걸린다는 점이다. 매번 BFS를 하는것과 같고, 그럼으로서 시간이 느릴수 밖에 없었다.

 

 

welog.tistory.com/61에서 풀었던 이모티콘 문제와 비슷한 방식으로 하면 된다. 문제 : www.acmicpc.net/problem/14226

 

14226번: 이모티콘

영선이는 매우 기쁘기 때문에, 효빈이에게 스마일 이모티콘을 S개 보내려고 한다. 영선이는 이미 화면에 이모티콘 1개를 입력했다. 이제, 다음과 같은 3가지 연산만 사용해서 이모티콘을 S개 만

www.acmicpc.net

이와 같은 문제는 BFS이기도 하지만, 각각의 BFS를 하는것보다, 한 타임씩 맞춰서 한꺼번에 하는 편이 시간을 절약하는데 도움이 되는 것 같다.

 

# 12851 숨바꼭질

N,M = map(int,input().split())
times = 0
ways = 0
prev_vistied = {N : 1}
visited = [True]*100001
if N == M:
    ways = 1
while not ways:
    new_visited = {}
    for number in prev_vistied:
        for new_number in [number-1,number+1,2*number]:
            if 0<= new_number <= 100000 and visited[new_number]:
                if new_number == M:
                    ways += prev_vistied[number]
                else:
                    if new_visited.get(new_number):
                        new_visited[new_number] += prev_vistied[number]
                    else:
                        new_visited[new_number] = prev_vistied[number]
    for visited_number in new_visited:
        visited[visited_number] = False
    prev_vistied = new_visited
    times += 1 

print(times)
print(ways)

개선한 방식은 다음과 같다. 

직전에 방문한 지점 prev_visited를 반복문을 돌리고, 방문하지 않았으면, new_visited에 prev_visited에서 누적된 해당 number에 올 수 있는 방법의 가지수를 더해주면 된다.

 

한번의 반복문이 끝나고 난뒤에, visited 함수에 방문을 한 것을 표시해주고, prev_visted를 new_visited로 변경시켜주면 된다.

 

이렇게 하면, 위의 BFS는 각각의 방법 하나하나마다 결과값에 도착할때까지 BFS를 하면서 반복문을 돌려야하지만, 이 방법은 number 단위로 해당 number에 올 수 있는 최소 타임을 이용해 한꺼번에, BFS를 한다는 점이다.

 

위와 같은 time을 세는 문제 같은 경우엔 일반적인 BFS가 아닌, 한 타임별로 전체를 반복문 돌리는 풀이방식도 생각해봐야겠다.

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

[BOJ/백준] 9633 N-queen  (0) 2021.01.28
[BOJ/백준] 2174 로봇 시뮬레이션  (0) 2021.01.26
[BOJ/백준] 2133 타일 채우기  (0) 2021.01.24
[BOJ/백준] 2251 물통  (0) 2021.01.23
[BOJ/백준] 2624 동전 바꿔주기  (0) 2021.01.22
# 2251 물통
#  A,B,C 
#  앞의 두 물통은 비어 있고, 세번째 물통은 가득 차 있다.
# A 물통이 비어있을때 세번째 물통에 담겨 있을 수 있는 물의 양을 구해내시오.
import collections 
max_Bowl = list(map(int,input().split()))
current_bowl = [0,0,max_Bowl[2]]
visited = [[[False]*(max_Bowl[2]+1) for _ in range(max_Bowl[1]+1)] for _ in range(max_Bowl[0]+1)]
# A,B,C
que = collections.deque()
que.appendleft((0,0,max_Bowl[2]))
result = set()
result.add(max_Bowl[2])
while que:
    cureent_water = que.popleft()
    if visited[cureent_water[0]][cureent_water[1]][cureent_water[2]]:
        continue
    if cureent_water[0] == 0:
        result.add(cureent_water[2])
    visited[cureent_water[0]][cureent_water[1]][cureent_water[2]] = True
    # A->B
    if cureent_water[0]+cureent_water[1] >= max_Bowl[1]:
        que.append((cureent_water[0]+cureent_water[1]-max_Bowl[1],max_Bowl[1],cureent_water[2]))
    else:
        que.append((0,cureent_water[0]+cureent_water[1],cureent_water[2]))
    # A->C
    if cureent_water[0]+cureent_water[2] >= max_Bowl[2]:
        que.append((cureent_water[0]+cureent_water[2]-max_Bowl[2],cureent_water[1],max_Bowl[2]))
    else:
        que.append((0,cureent_water[1],cureent_water[0]+cureent_water[2]))
    # B->C
    if cureent_water[1]+cureent_water[2] >= max_Bowl[2]:
        que.append((cureent_water[0],cureent_water[1]+cureent_water[2]-max_Bowl[2],max_Bowl[2]))
    else:
        que.append((cureent_water[0],0,cureent_water[1]+cureent_water[2]))
    # B->A
    if cureent_water[1]+cureent_water[0] >= max_Bowl[0]:
        que.append((max_Bowl[0],cureent_water[1]+cureent_water[0]-max_Bowl[0],cureent_water[2]))
    else:
        que.append((cureent_water[1]+cureent_water[0],0,cureent_water[2]))
    # C->A
    if cureent_water[2] + cureent_water[0] >= max_Bowl[0]:
        que.append((max_Bowl[0],cureent_water[1],cureent_water[2]+cureent_water[0]-max_Bowl[0]))
    else:
        que.append((cureent_water[2]+cureent_water[0],cureent_water[1],0))
    # C->B
    if cureent_water[2] + cureent_water[1] >= max_Bowl[1]:
        que.append((cureent_water[0],max_Bowl[1],cureent_water[2]+cureent_water[1]-max_Bowl[1]))
    else:
        que.append((cureent_water[0],cureent_water[2]+cureent_water[1],0))

result = sorted(list(result))
print(*result)

처음에 풀때 난잡하다. 똑같이 반복되는것을 계쏙 반복해주었다.

A->B,

A->C

B->C

B->A

C->A

C->B

의 과정을 거쳐주면서 방문하지 않은 경우에만 하는 방식으로 했다.

이렇게 하니 단순반복을 계속해서 쓰면서도 알아보기 힘들었다.

 

A,B,C = map(int,input().split())
def custom_append(a,b,c):
    global visited,stack,result
    if (a,b,c) not in visited:
        visited.add((a,b,c))
        stack.append((a,b,c))
        if a == 0:
            result.add(c)




def move_bowl(origin,target,target_max):
    if origin+target >= target_max:
        origin = origin+target- target_max
        target = target_max
    else:
        target = origin + target
        origin = 0
    return (origin,target)
visited = set()
visited.add((0,0,C))
stack = [(0,0,C)]
result = set()
result.add(C)

while stack:
    ca,cb,cc = stack.pop()
    if ca:
        # A->B
        na,nb = move_bowl(ca,cb,B)
        custom_append(na,nb,cc)
        # A->C
        na,nc = move_bowl(ca,cc,C)
        custom_append(na,cb,nc)
    if cb:
        # B->C
        nb,nc = move_bowl(cb,cc,C)
        custom_append(ca,nb,nc)
        # B->A
        nb,na = move_bowl(cb,ca,A)
        custom_append(na,nb,cc)
    if cc:
        # C->A
        nc,na = move_bowl(cc,ca,A)
        custom_append(na,cb,nc)
        # C->B
        nc,nb = move_bowl(cc,cb,B)
        custom_append(ca,nb,nc)

result = sorted(list(result))
print(*result)

좀 더 깔끔하게 바뀐 풀이방식이다.

 

물을 옮기는 과정을 하나의 함수로 만들어주었고, stack에 추가해주고 방문표시를 해주는것도 하나의 함수로 만들어줬다.

 

이렇게 하니, 본문에는 간단하게 남았고, 불필요한 코드를 반복해서 쓸필요성이 없어졌다.

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

[BOJ/백준] 12851 숨바꼭질 2  (0) 2021.01.25
[BOJ/백준] 2133 타일 채우기  (0) 2021.01.24
[BOJ/백준] 2624 동전 바꿔주기  (0) 2021.01.22
[BOJ/백준] 17142 연구소3  (0) 2021.01.22
[BOJ/백준] 1946 신입 사원  (0) 2021.01.22

+ Recent posts