import math
import sys
input = sys.stdin.readline
def init(node_number,start,end):
    global segement_tree,arr
    if start == end:
        segement_tree[node_number] = arr[start]
        return segement_tree[node_number]
    else:
        mid = (start+end)//2
        segement_tree[node_number] = min(init(node_number*2, start, mid) , init(node_number*2+1, mid+1, end))
        return segement_tree[node_number]

def find_min_number(node_number,start,end,left,right):
    global segement_tree,INF
    if (left > end) or (right<start):
        return INF
    if (left <= start) and (end<=right):
        return segement_tree[node_number]
    mid = (start+end)//2
    return min(find_min_number(node_number*2,start,mid,left,right), find_min_number(node_number*2+1,mid+1,end,left,right))

N,M = map(int,input().split())
INF = float('inf')
segement_tree = [-1]*(N*4+20)
arr = [int(input()) for _ in range(N)]
init(1,0,N-1)

for _ in range(M):
    left,right = map(int,input().split())
    print(find_min_number(1,0,N-1,left-1,right-1))

2042 구간 합 구하기와 동일한 세그먼트 트리 문제였다

 

동일하지만 구간합을 저장 하는 것이 아닌 최소값을 저장하는 것이 달라진 점이다 그 외에는 동일하게 해주면 된다.

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

[BOJ/백준] 1967 트리의 지름  (0) 2021.04.08
[BOJ/백준] 1806 부분합  (0) 2021.04.08
[BOJ/백준] 2042 구간 합 구하기  (0) 2021.03.12
[BOJ/백준] 2075 N번째 큰 수  (0) 2021.03.12
[BOJ/백준] 2252 줄 세우기  (0) 2021.03.12
import math
import sys
input = sys.stdin.readline
def init(node_number,start,end):
    global segement_tree,arr
    if start == end:
        segement_tree[node_number] = arr[start]
        return segement_tree[node_number]
    else:
       segement_tree[node_number] = init(node_number*2, start, (start+end)//2) + init(node_number*2+1, (start+end)//2+1, end)
       return segement_tree[node_number]

def update(node_number,start,end,index,diff):
    global segement_tree
    if (index < start) or (index > end):
        return
    segement_tree[node_number] = segement_tree[node_number] + diff
    if (start != end):
        update( node_number*2, start , (start+end)//2,index,diff)
        update(node_number*2+1, (start+end)//2+1,end,index,diff)

def sum_range(node_number,start,end,left,right):
    global segement_tree
    if (left > end) or (right<start):
        return 0
    if (left <= start) and (end<=right):
        return segement_tree[node_number]
    return sum_range(node_number*2,start,(start+end)//2,left,right) + sum_range(node_number*2+1,(start+end)//2+1,end,left,right)

N,M,K = map(int,input().split())
height = math.ceil(math.log2(N))
tree_size = 2**(height+1)-1
segement_tree = [0]*tree_size
arr = [int(input()) for _ in range(N)]

init(1,0,N-1)
cnt = M+K
while cnt:
    command,number1,number2 = map(int,input().split())
    if command == 1:
        diffrence = number2 - arr[number1-1]
        arr[number1 - 1] = number2
        update(1,0,N-1,number1-1,diffrence)
    else:
        print(sum_range(1,0,N-1,number1-1,number2-1))
    cnt -= 1

 

 

세그먼트 트리를 활용한 문제이다.

 

범위의 값을 저장하는 트리를 만들어두는 방식이고, 그걸 통해, 값이 변경 시 반복횟수를 줄이는 방식이다.

 

세그먼트 트리에 대해서 공부하면서 푼 문제라 아직 익숙하지 않다.

 

일단 기억하고 있는 세그먼트 트리의 기준은

 

세그먼트 트리로 만들고 싶은 원본 배열의 길이가 N이라고 할때

 

세그먼트 트리의 길이는 주어진 N보다 크거나 같은 2^k를 구하고, 이것의 2배를 하면 세그먼트 트리의 사이즈가 된다.

 

루트노드는 무조건 1이고,

 

루트노드의 왼쪽 노드는 2, 오른쪽 노드는 3이 된다.

 

 

세그먼트 트리에서 부모노드 A가 있을 때에 

 

A노드의 왼쪽 자식 노드는 A*2의 크기가 되고,

 

오른쪽 자식 노드는 A*2 + 1이 된다.

 

 

그리고 여기서 또 중요한 것은 범위이다.

 

특정 부모노드의 범위가 [left , rigiht] 이라고 할때, 

 

이 부모노드의 왼쪽 자식노드는 [left , (left+right)//2]가 되고

 

오른쪽 자식 노드는 [(left+right)//2 + 1, right] 가 된다.

 

이렇게 만들어주면 세그먼트 트리의 초기화가 가능하다.

 

이렇게 한뒤 특정 값의 갱신은 그 값이 갱신된 위치를 찾아, 그 변화량 만큼 바꿔주면 된다.

 

 

특정 범위 합은 범위를 벗어났을때, 범위안에 완전히 들어왔을때, 범위에 일부분 겹쳤을때로 나뉠수 있다.

 

이걸 이용해서 풀면된다.

 

위와 같이 세그먼트 트리를 위와 같이 주어진 조건에 맞춰서 만들고, 그 범위조차 원리에 맞게 만들어도 되지만, 쉽게 풀기 위하여, N 이 12라고 해도 N이 16일때와 같이 2의 제곱수의 크기만큼의 배열이 있다고 가정하고 만들어도 괜찮다.

 

 

import sys
import math
def init():
    global tree_size

    for i in range(tree_size-1,0,-1):
        segement_tree[i] = segement_tree[i*2] + segement_tree[i*2+1]


def update(index,diff):
    while index >= 1:
        segement_tree[index] += diff
        index//=2

def sum_range(node_number,start,end,left,right):
    if left > end or start > right:
        return 0
    if (left <= start) and (end <= right):
        return segement_tree[node_number]
    return sum_range(node_number*2,start,(start+end)//2,left,right) + sum_range(node_number*2+1,(start+end)//2+1,end,left,right)
input = sys.stdin.readline

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

height = math.ceil(math.log2(N))
tree_size = 2**height
total_size = 2**(height+1)

segement_tree = [0]*total_size

for i in range(N):
    segement_tree[tree_size + i] = int(input())

init()
for i in range(M+K):
    command = list(map(int,input().split()))
    if command[0] == 1:
        diff = command[2] - segement_tree[tree_size + command[1] - 1]
        update(command[1]+tree_size-1,diff)
    else:
        print(sum_range(1,0,tree_size-1,command[1]-1,command[2]-1))

세그먼트 트리 자체를 2의 제곱수의 크기일때로 생각하고  넣어주는 방식으로 푸는 방식이다.

 

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

[BOJ/백준] 1806 부분합  (0) 2021.04.08
[BOJ/백준] 10868 최소 값 찾기  (0) 2021.03.20
[BOJ/백준] 2075 N번째 큰 수  (0) 2021.03.12
[BOJ/백준] 2252 줄 세우기  (0) 2021.03.12
[BOJ/백준] 11066 파일 합치기  (0) 2021.03.12
import heapq
import sys

input = sys.stdin.readline
N = int(input())
arr = []
for _ in range(N):
    temp = list(map(int,input().split()))
    for number in temp:
        heapq.heappush(arr,number)
    while len(arr) > N:
        heapq.heappop(arr)



result = heapq.heappop(arr)
print(result)

N번째 큰수를 구하는 거였고, N의 최대값이 1500이므로, 전체 input을 받아서 행렬을 만드는게 아닌, 

 

한 행이 들어올때마다 판별을 해줘야한다고, 생각했다.

 

그리고 우리가 구하고 싶은 것은 N번째 이므로, 저장할 칸은 N 칸만 있으면 된다고 생각했고, 이걸 heapq를 이용해서 구현했다.

 

처음 구현한 방식은 일단 한 행을 전부 집어넣고, 리스트의 길이가 N이 될때까지 heappop을 계속 해주었다. 

 

그리고 마지막으로 heappop을 해서 원하는 결과를 얻었다.

 

 

import heapq
import sys

input = sys.stdin.readline

N = int(input())
arr = []

for i in range(N):
    input_list = map(int,input().split())
    if i == 0 :
        for number in input_list:
            heapq.heappush(arr,number)
    else:
        for number in input_list:
            if number > arr[0]:
                heapq.heappushpop(arr,number)
big_list = heapq.nlargest(N,arr)
print(big_list[N-1])

 

두번째 방법은 heapq 모듈을 좀 더 활용하는 방법이다.  무조건 넣고 길이 N이 될때까지 계속 pop 하는 것이 아닌.

 

heappushpop을 쓰는 것이다. 이것은 heap에 먼저 push를 한뒤에 가장 작은 값을 pop 하는 것으로,

 

heappush와 heappop을 쓰는 것보다 실행속도가 더 빠르다.

 

그리고 마지막으로 heapq.nlargest를 쓰는 것이다. 이 메소드는 정의된 요소에서 가장 큰 순서대로 n개로 구성된 리스트를 반환해주는 메소드이다. 이걸 이용하면, 정렬을 한 효과와 동일하다.

 

# stkang9409 풀이 해석

def find_max_value(x):
    return arr[max_row_list[x]][x]

import sys

input = sys.stdin.readline


N = int(input())
arr = [list(map(int,input().split())) for _ in range(N)]

max_row_list = [N-1]*N
# 각 열마다 가장 큰 값은 N-1번 행에 있는 값이다.
# 매번 돌면서 각 열마다 가장 큰값들을 비교해, 가장 큰 값이 있는 열의 index 값을 하나씩 줄여나간다.
# 그렇게 하면 마지막 N번째에 가장 큰 값을 가지는 열의 값이 N번째로 큰 수의 열값이 되고
# 그 때 저장된 위치의 값이 행이된다.
for cnt in range(N):
    max_col_index = 0
    for col in range(N):
        max_col_index = max(col,max_col_index,key= find_max_value)
    if cnt == N-1:
        print(arr[max_row_list[max_col_index]][max_col_index])
    max_row_list[max_col_index] -= 1

마지막 풀이는 stkang9409님 코드를 보고 분석하것이다.

이 방법은 heapq를 쓴 것이 아닌, 문제의 조건을 보고 푼 방식이다.

 

위의 heapq를 쓴다면 신경 안 쓸 조건이지만, 문제에 주어진 조건을 보면

 

각 열의 값들은 그 다음행의 값보다 작다는 것이다. 즉 A열의 B행의 값은 B+1행보다는 무조건 작다는 것이다.

 

이 점을 이용해 N번째로 큰 값을 알 수 있다.

 

 

만약 조건 N이 주어진다면

 

각 열마다 가장 큰 행의 위치는 N-1일것이다. (0행부터 시작한다)

 

이걸 하나의 리스트로 구성하면

max_row_list = [N-1, N-1,.... N-1]

일것이고, 이 리스트의 인덱스는 arr의 열의 값이 될것이고, 해당 index의 값은 행이 될것이다.

 

각 열에서의 최대값을 비교해서 가장 큰 값을 구해준다.

 

각 열의 최대값은 arr[ max_row_list[ind] ] [ ind ] 가 될 것이다.

 

이렇게 하면 가장 큰 값이 있는 열의 값을 구할 수 있다. 그 열의 값이 있는 max_row_list의 값을 1을 낮춰준다.

 

이런 식으로 반복 하면 N번 반복하면 N번째로 큰 수를 알 수 있다.

 

 

예시 ) 

12 7 9 15 5

13 8 11 19 6

21 10 26 31 16

48 14 28 35 25

52 20 32 41 49

 

위와 같이 주어지면 

 

max_row_index = [4,4,4,4,4] 가 될 것이다.

 

--  1번째  --

 

arr[4][0],arr[4][1],arr[4][2],arr[4][3],arr[4][4] 의 값을 비교해보면 arr[0][4]가 가장 작다.

 

그러면 max_row_index 의  0번 인덱스의 값을 1 줄여준다,

 

max_row_index = [3,4,4,4,4] 가 된다.

 

-- 2번째 --

 

arr[3][0],arr[4][1],arr[4][2],arr[4][3]arr[4][4] 의 값을 비교해보면 arr[4][4]의 49가 가장 크다.

 

그러면 4번 인덱스이고 해당 max_row_index의 값을 줄여준다.

 

max_row_index = [3,4,4,4,3]

 

-- 3번째 --

 

arr[3][0],arr[4][1],arr[4][2],arr[4][3]arr[3][4] 의 값을 비교해보면 arr[3][0]의 48이 가장 크다.

 

그러면 0번 인덱스이고 해당 max_row_index의 값을 줄여준다.

 

max_row_index = [2,4,4,4,3]

 

 

-- 4번째 --

 

arr[2][0],arr[4][1],arr[4][2],arr[4][3]arr[3][4] 의 값을 비교 해보면  arr[4][3]의 41이 가장 크다.

 

그러면 3번 인덱스이고 해당 max_row_index의 값을 줄여준다.

 

max_row_index = [2,4,4,3,3] 

 

--5번째 (마지막) --

 

arr[2][0],arr[4][1],arr[4][2],arr[3][3],arr[3][4] 의 값을 비교 해보면 arr[3][3]의 35이 가장 크다

 

그리고 우리가 구하던 N번째로 큰 값이므로 이 값을 그대로 출력해주면 된다.

 

 

설명이 많이 부족하겠지만, 최대한 자세히 설명을 했다.

 

 

마지막 풀이는 문제의 조건을 활용해 각 열을 기준으로 하는 최대 행을 저장해주는 리스트를 만들어두고

 

각 열의 최대값을 갱신해주면서 하는 방식으로 보면 된다. 

 

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

[BOJ/백준] 10868 최소 값 찾기  (0) 2021.03.20
[BOJ/백준] 2042 구간 합 구하기  (0) 2021.03.12
[BOJ/백준] 2252 줄 세우기  (0) 2021.03.12
[BOJ/백준] 11066 파일 합치기  (0) 2021.03.12
[BOJ/백준] 1300 K번째 수  (0) 2021.03.11
import sys

input = sys.stdin.readline

from collections import deque

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

graph = [{} for _ in range(N+1)]
parents_cnt = [0]*(N+1)
result = []
visited = [True]*(N+1)
for _ in range(M):
    A,B = map(int,input().split())
    graph[A][B] = 1
    parents_cnt[B] += 1

que = deque()
for i in range(1,N+1):
    if not parents_cnt[i]:
        que.append(i)
for i in range(N):
    x = que.popleft()
    result.append(x)

    for next_node in graph[x]:
        parents_cnt[next_node] -= 1
        if parents_cnt[next_node] == 0:
            que.append(next_node)
print(*result)


m.blog.naver.com/ndb796/221236874984

 

25. 위상 정렬(Topology Sort)

위상 정렬(Topology Sort)은 '순서가 정해져있는 작업'을 차례로 수행해야 할 때 그 순서를 결정해주기 ...

blog.naver.com

 

위상정렬에 관련된 처음 보는 문제였고, 순서가 정해진 작업을 차례대로 작업할 순서를 정할때 쓰는 알고리즘이라는 것을 알았다.

 

이 알고리즘에 대해 더 공부하고, 기본 틀을 완성시켜놔야할것 같다.

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

[BOJ/백준] 2042 구간 합 구하기  (0) 2021.03.12
[BOJ/백준] 2075 N번째 큰 수  (0) 2021.03.12
[BOJ/백준] 11066 파일 합치기  (0) 2021.03.12
[BOJ/백준] 1300 K번째 수  (0) 2021.03.11
[BOJ/백준] 5052 전화번호 목록  (0) 2021.03.11
import sys
input = sys.stdin.readline

T = int(input())

def divide_two(ind_X,ind_Y):
    if ind_X == ind_Y:
        return books[ind_X]
    cache_data = dp[ind_X][ind_Y]
    if cache_data != -1:
        return cache_data

    temp = float('inf')
    mid_sum = prefix_sum[ind_Y+1] - prefix_sum[ind_X]
    for k in range(ind_X,ind_Y):
        temp = min(temp,divide_two(ind_X,k)+divide_two(k+1,ind_Y)+mid_sum)
    dp[ind_X][ind_Y] = temp
    return temp

    

for _ in range(T):

    N = int(input())
    dp = [[-1]*N for _ in range(N)]
    books = list(map(int,input().split()))
    prefix_sum = [0]*(N+1)
    for i in range(1,N+1):
        prefix_sum[i] = prefix_sum[i-1] + books[i-1]
    result = float('inf')

    for i in range(N-1):
        result = min(result,divide_two(0,i)+divide_two(i+1,N-1))

    print(result)

어렵게 푼 문제이다.

 

먼저 특정 범위의 합을 구해야하기 때문에, prefix_sum을 먼저 구해준다.

 

그리고 재귀를 통해, 특정 위치로 나누었을때의 최소값을 구하는 함수를 통해 구해준다.

 

만약 0~N-1 칸이 있다고 했을때, 0~i 와 i+1~N-1을 나눠서 소분해서 구해주면 된다.

 

전체 0~N-1칸을 생각해보지 말고, 

 

작은 공간 A ~ A+2 칸이 있다고 해보자,

A   | |   A+1   | |   A+2

30  | |   40     | |    50 

 

라고 하면

 

1번 경우 : 30 // 40 + 50

 

2번 경우 : 30 + 40 // 50

 

각각을 구해보면

 

1번 경우 : 90 + 90 + 30 = 90 + 120 = 210

2번 경우 : 70 + 70 + 50 = 70 + 120 = 190

 

그러면 A~A+2칸에서 가장 적게 구하는 것은 30+40 // 50 일때이다.

 

그리고 위의 경우를 봐보면 120은 30 + 40 + 50을 다 더한거와 같고, 그 앞의 값만 바뀐다는 것을 알 수 있다.

 

이걸 식으로 표현하면 divide_two(A,ind) + divide_two(ind+1,B) + (books[A] + books[A+1] + books[A+2]) 

 

가 된다.

 

결국 정리하면 divide_two라는 함수에 들어왔을때 ind_X 와 ind_Y가 같으면 books[ind_X]의 값을 반환해주면 되고,

 

그 외의 경우에는 ind_X와 ind_Y의 사이값으로 나뉘었을때를 가정하고, 재귀를 통해 최소값을 구해주면 된다.

 

또한 이렇게 구한 값들은 변하지 않기 때문에

 

dp에 저장을 해주면 된다. dp[ind_X][ind_Y] 는 ind_X에서 ind_Y 까지의 범위를 계싼했을때 최저 값인 것이다.

 

위와 같이 구하면 파일 합치기의 최소값을 구할 수 있다.

 

하지만 이 방법은 N^3을 돌기 때문에 시간이 오래걸린다.

 

그래서 다른 사람들의 풀이를 보고 찾은 방법은 다음과 같다.

 

 

# # Knuth's Optimization
# # https://wogud6792.tistory.com/20

import sys
input = sys.stdin.readline

T = int(input())

for _ in range(T):
    N = int(input())
    books = list(map(int,input().split()))
    prefix_sum = [0]*(N+1)
    INF = float('inf')
    dp =[[INF] *N for _ in range(N)]
    min_k_store_array = [[0]*N for _ in range(N)]
    for i in range(N):
        dp[i][i] = 0
        min_k_store_array[i][i] = i
        prefix_sum[i+1] = prefix_sum[i] + books[i]
    for term in range(1,N):
        for i in range(N-term):
            j = term+i
            for k in range(min_k_store_array[i][j-1],min_k_store_array[i+1][j]+1):
                if k<N-1 and dp[i][j] > dp[i][k]+dp[k+1][j]+ prefix_sum[j+1] - prefix_sum[i]:
                    dp[i][j] = dp[i][k]+dp[k+1][j] + prefix_sum[j+1] - prefix_sum[i]
                    min_k_store_array[i][j] = k
    print(dp[0][N-1])

 https://wogud6792.tistory.com/20

 

위의 블로그에 설명이 잘 되어 있으니 참조 바란다.

 

DP에서 특정한 조건을 만족할 경우, 최적활 할 수 있는 기법이다.

 

위의 최적화 기법의 점화식을 보고 구현한 것이다.

 

최적화 기법이므로, 실행속도가 확연히 줄어든다.

 

하지만 저는 실전에서는 쓰기 힘들것 같다. 쓸려면 이 Knuth Optimization에 대해서 더 공부해야할 것 같다.

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

[BOJ/백준] 2075 N번째 큰 수  (0) 2021.03.12
[BOJ/백준] 2252 줄 세우기  (0) 2021.03.12
[BOJ/백준] 1300 K번째 수  (0) 2021.03.11
[BOJ/백준] 5052 전화번호 목록  (0) 2021.03.11
[BOJ/백준] 1963 소수 경로  (0) 2021.03.11
N = int(input())
K = int(input())
ST,EN = 1,K
while ST<=EN:
    mid = (ST+EN)//2
    cnt = 0
    for i in range(1,N+1):
        cnt += min(mid//i,N)

    if cnt < K:
        ST = mid + 1
    else:
        EN = mid -1

print(ST)

코드는 간단하지만, 어려웠던 문제였다.

 

자세한 설명은 다른 사람 블로그를 참조하길 바란다.

 

몇몇 케이스를 해보면 알지만 K번째의 수는 절대 K를 넘을 수가 없다.

 

이점을 이용해 1,K로 이분탐색을 한다.

 

각 행을 i라고 하면, 각 행은 i의 배수이다. 

 

즉 N = 5라고 하면 총 5행이 있고, 우리가 찾고자 하는 T = 12 라고 하면

 

1행에서 12보다 작거나 같은 값은 1,2,3,4,5          T//1 = 12

2행에서 12보다 작거나 같은 값은 2,4,6,8,10        T//2 = 6

3행에서 12보다 작거나 같은 값은 3,6,9,12,          T//3 = 4

4행에서 12보다 작거나 같은 값은 4,8,12,            T//4 = 3

5행에서 12보다 작거나 같은 값은 5,10               T//5 = 2

 

위와 같이 보면 우리가 찾고자 하는 값보다 작은 값의 개수는 각 행의 값을 나눈 몫 만큼이다. 그리고 각 행의 열의 개수는 N이므로, N과 비교해서 최소값으로 한다.

 

이분 탐색을 반복하면서 특정 값보다 작거나 같은 값의 개수가 K개가 될때까지 반복해준다. 또한 ST == END가 될때까지 반복해준다. 왜냐하면 K가 되는 값이 여러개가 될수 있으므로, 특정해줘야한다.

K개 에서 그냥 빠져 나올 경우 

N=52, K=276

에서 답이 잘못 나온다.

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

[BOJ/백준] 2252 줄 세우기  (0) 2021.03.12
[BOJ/백준] 11066 파일 합치기  (0) 2021.03.12
[BOJ/백준] 5052 전화번호 목록  (0) 2021.03.11
[BOJ/백준] 1963 소수 경로  (0) 2021.03.11
[BOJ/백준] 1504 특정한 최단 경로  (0) 2021.03.11
T = int(input())
def check(arr):
    for ind in range(len(arr)-1):
        if arr[ind] == arr[ind+1][:len(arr[ind])]:
            return 'NO'
    return 'YES'



for _ in range(T):
    N = int(input())
    phone_list = [input() for _ in range(N)]
    phone_list.sort()
    print(check(phone_list))

 

문자열인체로 정렬을 하면, 앞에서부터 숫자가 작은순으로 정렬이 된다. 

 

이 점을 이용해, 앞에서부터 하나씩 그 다음 문자열과 앞에서부터 같은지 확인해주면 된다.

 

import sys

input = sys.stdin.readline

T = int(input())
def check(arr):
    for ind in range(len(arr)-1):
        if arr[ind+1].startswith(arr[ind]):
            return 'NO'
    return 'YES'



for _ in range(T):
    N = int(input())
    phone_list = [input().strip() for _ in range(N)]
    phone_list.sort()
    print(check(phone_list))

startswith라는 메소드를 활용해서 하는 방법도 있다.

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

[BOJ/백준] 11066 파일 합치기  (0) 2021.03.12
[BOJ/백준] 1300 K번째 수  (0) 2021.03.11
[BOJ/백준] 1963 소수 경로  (0) 2021.03.11
[BOJ/백준] 1504 특정한 최단 경로  (0) 2021.03.11
[BOJ/백준] 15685 드래곤 커브  (0) 2021.03.08
import sys

input = sys.stdin.readline
def findprimenumber():
    global prime_number
    prime_number[1] = False
    prime_number[0] = False
    for i in range(2,10001):
        if prime_number[i]:
            for j in range(i+i,10001,i):
                prime_number[j] = False





T = int(input())
prime_number = [True]*10001
findprimenumber()
for _ in range(T):
    A,B = map(int,input().split())
    result = 'Impossible'
    visited = [-1] * 10001
    if A == B:
        print(0)
    else:
        stack = [A]
        cnt = 0
        while stack:
            new_stack = []
            for number in stack:
                number_list = list(map(int,list(str(number))))
                for ind in range(4):
                    if ind == 0:
                        for k in range(1,10):
                            if number_list[ind] != k:
                                new_number = k*1000 + 100*number_list[1] + 10*number_list[2] + number_list[3]
                                if visited[new_number] == -1 and prime_number[new_number]:
                                    visited[new_number] = cnt+1
                                    new_stack.append(new_number)
                    else:
                        for k in range(10):
                            if number_list[ind] != k:
                                new_number = number - number_list[ind]*(10**(3-ind)) + k*(10**(3-ind))
                                if visited[new_number] == -1 and prime_number[new_number]:
                                    visited[new_number] = cnt+1
                                    new_stack.append(new_number)
            if B in new_stack:
                result = cnt + 1
                break
            stack = new_stack[:]
            cnt += 1
        print(result)
        
        

문제는 소수를 구하는 것과 BFS를 활용하면 되는 문제였다.

먼저 자신만의 방법으로 문제에서 주어진 10000 까지의 소수를 구한다.

나는 단순하게 반복문을 통해서 구했고, True False로 구분이 되게 해주었다.

 

이 상황에서 주어진 넘버에서 각자리 수를 변경하면서, 방문하지 않았고 소수일때에 new_stack에 넣어주는 방식으로 했다.

 

 

import sys

input = sys.stdin.readline


prime_number = [True]*10000
prime_number[0] = False
prime_number[1] = False

for k in range(2,10000):
    if prime_number[k]:
        for j in range(k+k,10000,k):
            prime_number[j] = False

T = int(input())

for _ in range(T):
    A,B = map(int,input().split())
    if A == B:
        print(0)
    else:
        visited = [True]*10000
        result = 'Impossible'
        stack = [A]
        cnt = 0
        while stack:
            new_stack = set()
            for number in stack:
                for k in [1,10,100,1000]:
                    fall_number = number - (number//k)%10*k
                    for i in range(10):
                        new_number = fall_number + i *k
                        if prime_number[new_number] and visited[new_number] and new_number >= 1000:
                            visited[new_number] = False
                            new_stack.add(new_number)
            if B in new_stack:
                result = cnt + 1
                break
            stack = list(new_stack)[:]
            cnt += 1
        print(result)

 좀 더 깔끔한 방법으로 자리수 변경을 한 방식이다. 주어진 넘버에서 바꾸고 싶은 자리수로 나눈 몫의 10으로 나눈 나머지를 구하면, 해당 자리수를 구할 수 있다. 이 방식을 이용해서, 구현했다.

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

[BOJ/백준] 1300 K번째 수  (0) 2021.03.11
[BOJ/백준] 5052 전화번호 목록  (0) 2021.03.11
[BOJ/백준] 1504 특정한 최단 경로  (0) 2021.03.11
[BOJ/백준] 15685 드래곤 커브  (0) 2021.03.08
[BOJ/백준] 2096 내려가기  (0) 2021.03.08

+ Recent posts