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


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


def find_parents(X):
    if X == make_set[X]:
        return X
    make_set[X] = find_parents(make_set[X])
    return make_set[X]


def union(x,y):
    X = find_parents(x)
    Y = find_parents(y)

    if X !=Y:
        if ranks[X]< ranks[Y]:
            X,Y = Y,X
        make_set[Y] = X
        if ranks[X] == ranks[Y]:
            ranks[X] += 1
        return True
    return False


T = int(input())


for tc in range(1,T+1):
    N = int(input())
    make_set = [i for i in range(N)]
    ranks = [1 for _ in range(N)]

    for _ in range(int(input())):
        x,y = map(int,input().split())
        union(x,y)
    print(f'Scenario {tc}:')
    for _ in range(int(input())):
        x,y = map(int,input().split())
        if find_parents(x) != find_parents(y):
            print(0)
        else:
            print(1)

    if tc != T:
        print()

전형적인 분리집합 문제였다.

 

 

들어오는 입력대로 union을 해주었고, 서로의 부모가 다를시에는 0 같을 시에는 1이 출력되게 했다.

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

def cycle_check(node,parent):
    if visited[node]:
        return node
    else:
        visited[node] = True
        for next_node in graph[node]:
            if next_node == parent:continue
            return_node = cycle_check(next_node,node)
            if return_node > 0:
                cycle_check_node[node] = True
                if return_node == node:
                    return 0
                else:
                    return return_node
        cycle_check_node[node] = False
        return 0
def dfs(start):
    stack = [(start,0,0)]
    visited = [True for _ in range(N+1)]
    while stack:
        node,parent,dis = stack.pop()

        if cycle_check_node[node]:
            distance[start] = dis
            return
        visited[node] = False

        for next_node in graph[node]:
            if next_node == parent:continue
            if visited[next_node]:
                stack.append((next_node,node,dis+1))



N = int(input())

graph = [[] for _ in range(N+1)]

for _ in range(N):
    x,y = map(int,input().split())
    graph[x].append(y)
    graph[y].append(x)


visited = [False for _ in range(N+1)]
cycle_check_node = [False for _ in range(N+1)]
distance = [0 for _ in range(N+1)]

cycle_check(1,0)


for k in range(1,N+1):
    if not cycle_check_node[k]:
        dfs(k)


print(*distance[1:])

  처음 풀이는 생각나는대로 풀었다. 먼저 2가지 함수로 나눠서 했다.

 

처음은 cycle을 체크하는 함수이다. 어느 노드에서든지 시작을 해서, 한번 방문을 했던 노드가 나올때까지

 

부모노드를 제외한 자식노드를 탐색해간다. 그러다보면 cycle의 시작지점을 방문하게 되는데 이때,

 

우리는 해당 node의 번호를 리턴해준다. 그러면 우리는 return 된 값이 0보다 크면

 

이 노드는 사이클에 포함된 노드임을 알 수 있다. 그러므로 return이 된 값이 0보다 크면 cycle임을 체크해주고,

 

시작지점에 도착하면, return 된 node와 값이 같으므로, 그걸로 판별뒤, 그 뒤에는 0을 반환해주면 된다.

 

그러면 우리는 0이 반환이 되면, 해당 노드는 사이클이 아닌것을 알게 된다.

 

이렇게 cycle을 체크한 뒤에

 

dfs를 돌려 cycle을 최초로 만나는 지점까지의 거리를 구해서 저장해주면 된다.

 

 

 

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

def cycle_check(node,parent):
    if visited[node]:
        return node
    else:
        visited[node] = True
        for next_node in graph[node]:
            if next_node == parent:continue
            return_node = cycle_check(next_node,node)
            if return_node > 0:
                cycle_check_node[node] = True
                distance[node] = 0
                if return_node == node:
                    return 0
                else:
                    return return_node
        cycle_check_node[node] = False
        return 0
def dfs(start,parent):
    if distance[start] != INF:
        return distance[start]
    for next_node in graph[start]:
        if next_node == parent:continue
        distance[start] = min(dfs(next_node,start)+1,distance[start])

    return distance[start]

    



N = int(input())

graph = [[] for _ in range(N+1)]

for _ in range(N):
    x,y = map(int,input().split())
    graph[x].append(y)
    graph[y].append(x)


visited = [False for _ in range(N+1)]
cycle_check_node = [False for _ in range(N+1)]
INF = float('inf')
distance = [INF for _ in range(N+1)]

cycle_check(1,0)

for k in range(1,N+1):
    if not cycle_check_node[k] and distance[k] == INF:
        dfs(k,0)

print(*distance[1:])

이 방식은 좀 더 깔끔한 코드이다. 모든 노드들을 dfs를 각각돌리는것이 아닌. cycle인 부분에서부터 1씩 거리를 늘리면서 하나씩 해주는 방식이다.

 

이 방식이 좀 더 깔끔한 방식이다.

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

[BOJ/백준] 13397 구간 나누기 2  (0) 2021.07.12
[BOJ/백준] 4358 생태학  (0) 2021.07.12
[BOJ/백준] 16472 고냥이  (0) 2021.06.29
[BOJ/백준] 16398 행성 연결  (0) 2021.06.29
[BOJ/백준] 15661 링크와 스타트  (0) 2021.06.29
import sys
from collections import deque
input = sys.stdin.readline

def bfs(x,y):

    queue = deque()
    queue.append((x,y))
    visited[x][y] = False
    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<M:
                if visited[nx][ny] and arr[nx][ny] >= T:
                    visited[nx][ny] = False
                    queue.append((nx,ny))


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

arr = []

for x in range(N):
    input_list = list(map(int,input().split()))
    temp = []
    for k in range(M):
        temp.append(sum(input_list[3*k:3*(k+1)]))

    arr.append(temp)

T = int(input())

T = 3*T


visited = [[True for _ in range(M)] for _ in range(N)]

dx = [-1,1,0,0]
dy = [0,0,-1,1]

cnt = 0
for x in range(N):
    for y in range(M):
        if arr[x][y] >= T  and visited[x][y]:
            bfs(x,y)
            cnt += 1

print(cnt)

 

 

이 문제는 처음들어올때부터 값을 계산해주는 방식으로 했다.

 

이 문제를 평균값을 구하면 float 값이 나올것 같아서, 어차피 문제에서 경계값이 정수이고,

 

한 픽셀을 구성하는 것은 3개로 고정적이므로 처음에 들어올때 열을 기준으로 3개씩 짤라주면서 그때의 합을 전부 저장하는 방식으로 했다.

 

이렇게 변형햔 배열을 가지고 BFS를 하면 되는데

 

계산의 편의성을 위해 경계값이 들어오자마자 그냥 3배를 해주었다.

 

그리고 난뒤에는 일반적인 BFS,DFS를 해주면 되는 문제이다.

 

방문을 하지않고, 경계값을 넘는 위치에 대해 bfs를 해서 인접한 픽셀들을 구하고, 함수가 끝난뒤에 개수를 늘려주었다.

 

 

import sys
input = sys.stdin.readline
N,M = map(int,input().split())

graph = [[] for _ in range(N+1)]
for _ in range(M):
    x,y = map(int,input().split())
    graph[y].append(x)


start = int(input())
stack = [start]
cnt = 0
visited = [True for _ in range(N+1)]
visited[start] = False
while stack:
    x = stack.pop()

    for next_node in graph[x]:
        if visited[next_node]:
            visited[next_node] = False
            cnt += 1
            stack.append(next_node)

print(cnt)

주어진 작업을 시행하기위해서 필요한 작업의 양을 구하는 방법은

 

처음에 들어온 입력을 자식노드에 부모노드를 기억해놓고,

 

주어진 노드에서부터, 부모로 가면서 부모의 수를 세어주면 된다.

 

 

  

from collections import deque

N = int(input())
if N == 1:
    print(0)
    print(1)
else:
    dp_dict = {N:-1}
    stack = [N]
    cnt = 0
    while stack:
        new_stack = []
        for num in stack:
            if not (num%3 or dp_dict.get(num//3)):
                dp_dict[num//3] = num
                new_stack.append(num//3)
            if not (num%2 or dp_dict.get(num//2)):
                dp_dict[num//2] = num
                new_stack.append(num//2)
            
            if not dp_dict.get(num-1) and num>1:
                dp_dict[num-1] = num
                new_stack.append(num-1)
        cnt += 1
        if 1 in new_stack:
            break
        stack = new_stack[:]
    result = []

    find_num = 1
    print(cnt)
    while True:
        result.append(find_num)
        find_num = dp_dict[find_num]
        if find_num == -1:
            break
    result.reverse()
    print(*result)


 

 

방식은 간단하다. 나눠지고, 해당 값이 최초로 방문했을때에만 new_stack에 넣어주고,

 

그때의 위치정보를 dictionary에 저장시켜준다.

 

그리고 1에 도착하면 역으로 추적해가면서 최초의 숫자가 나올때까지 반복을 해주면 되는 문제이다.

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

[BOJ/백준] 14950 정복자  (0) 2021.06.06
[BOJ/백준] 14725 개미굴  (0) 2021.06.06
[BOJ/백준] 12764 싸지방에 간 준하  (0) 2021.06.06
[BOJ/백준] 11085 군사이동  (3) 2021.06.06
[BOJ/백준] 10421 수식 완성하기  (0) 2021.06.06

+ Recent posts