728x90
반응형

문제:

N×M (5≤N, M≤100)의 모눈종이 위에 아주 얇은 치즈가 <그림 1>과 같이 표시되어 있다. 단, N 은 세로 격자의 수이고, M 은 가로 격자의 수이다. 이 치즈는 냉동 보관을 해야만 하는데 실내온도에 내어놓으면 공기와 접촉하여 천천히 녹는다. 그런데 이러한 모눈종이 모양의 치즈에서 각 치즈 격자(작 은 정사각형 모양)의 4변 중에서 적어도 2변 이상이 실내온도의 공기와 접촉한 것은 정확히 한시간만에 녹아 없어져 버린다. 따라서 아래 <그림 1> 모양과 같은 치즈(회색으로 표시된 부분)라면 C로 표시된 모든 치즈 격자는 한 시간 후에 사라진다.

<그림 2>와 같이 치즈 내부에 있는 공간은 치즈 외부 공기와 접촉하지 않는 것으로 가정한다. 그러므 로 이 공간에 접촉한 치즈 격자는 녹지 않고 C로 표시된 치즈 격자만 사라진다. 그러나 한 시간 후, 이 공간으로 외부공기가 유입되면 <그림 3>에서와 같이 C로 표시된 치즈 격자들이 사라지게 된다.

모눈종이의 맨 가장자리에는 치즈가 놓이지 않는 것으로 가정한다. 입력으로 주어진 치즈가 모두 녹아 없어지는데 걸리는 정확한 시간을 구하는 프로그램을 작성하시오.

입력:

첫째 줄에는 모눈종이의 크기를 나타내는 두 개의 정수 N, M (5 ≤ N, M ≤ 100)이 주어진다. 그 다음 N개의 줄에는 모눈종이 위의 격자에 치즈가 있는 부분은 1로 표시되고, 치즈가 없는 부분은 0으로 표시된다. 또한, 각 0과 1은 하나의 공백으로 분리되어 있다.

출력:

출력으로는 주어진 치즈가 모두 녹아 없어지는데 걸리는 정확한 시간을 정수로 첫 줄에 출력한다.

풀이방법:

https://codedrive.tistory.com/470

2636. 치즈 문제에서 조건이 하나 더 추가된 문제다. 2636 문제에 delete 배열을 이용해서 접한 횟수를 추가적으로 세서, 2 이상인 경우에만 치즈가 녹게 하면 된다.

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
31
32
33
34
35
36
37
38
39
40
41
42
from collections import deque
 
dx = [0,1,0,-1]
dy = [1,0,-1,0]
 
def bfs(i,j):
    queue = deque([(i,j)])
    visited = [[0 for _ in range(M)] for _ in range(N)]
    visited[i][j] = -1
    exist = 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 and not visited[nx][ny]:
                if cheese[nx][ny]:
                    delete[nx][ny]+=1
                    exist = True
                else:
                    visited[nx][ny] = -1
                    queue.append((nx,ny))
    for i in range(N):
        for j in range(M):
            if delete[i][j] >= 2:
                cheese[i][j] = 0
    return exist
 
N, M = map(int,input().split())
cheese = []
for _ in range(N):
    cheese.append(list(map(int,input().split())))
    
time = 0
while True:
    delete = [[0 for _ in range(M)] for _ in range(N)]
    conti = bfs(0,0)
    if conti:
        time+=1
    else:
        break
print(time)
cs

문제링크:

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

 

2638번: 치즈

첫째 줄에는 모눈종이의 크기를 나타내는 두 개의 정수 N, M (5 ≤ N, M ≤ 100)이 주어진다. 그 다음 N개의 줄에는 모눈종이 위의 격자에 치즈가 있는 부분은 1로 표시되고, 치즈가 없는 부분은 0으로

www.acmicpc.net

 

728x90
반응형

'Algorithm > Python' 카테고리의 다른 글

[BOJ]2110. 공유기 설치  (0) 2021.09.09
[BOJ]17406. 배열 돌리기 4  (0) 2021.09.08
[BOJ]2636. 치즈  (0) 2021.09.03
[BOJ] 11054. 가장 긴 바이토닉 부분 수열  (0) 2021.09.02
[BOJ]2565. 전깃줄  (0) 2021.09.01
728x90
반응형

문제:

아래 <그림 1>과 같이 정사각형 칸들로 이루어진 사각형 모양의 판이 있고, 그 위에 얇은 치즈(회색으로 표시된 부분)가 놓여 있다. 판의 가장자리(<그림 1>에서 네모 칸에 X친 부분)에는 치즈가 놓여 있지 않으며 치즈에는 하나 이상의 구멍이 있을 수 있다.

이 치즈를 공기 중에 놓으면 녹게 되는데 공기와 접촉된 칸은 한 시간이 지나면 녹아 없어진다. 치즈의 구멍 속에는 공기가 없지만 구멍을 둘러싼 치즈가 녹아서 구멍이 열리면 구멍 속으로 공기가 들어가게 된다. <그림 1>의 경우, 치즈의 구멍을 둘러싼 치즈는 녹지 않고 ‘c’로 표시된 부분만 한 시간 후에 녹아 없어져서 <그림 2>와 같이 된다.

다시 한 시간 후에는 <그림 2>에서 ‘c’로 표시된 부분이 녹아 없어져서 <그림 3>과 같이 된다.

<그림 3>은 원래 치즈의 두 시간 후 모양을 나타내고 있으며, 남은 조각들은 한 시간이 더 지나면 모두 녹아 없어진다. 그러므로 처음 치즈가 모두 녹아 없어지는 데는 세 시간이 걸린다. <그림 3>과 같이 치즈가 녹는 과정에서 여러 조각으로 나누어 질 수도 있다.

입력으로 사각형 모양의 판의 크기와 한 조각의 치즈가 판 위에 주어졌을 때, 공기 중에서 치즈가 모두 녹아 없어지는 데 걸리는 시간과 모두 녹기 한 시간 전에 남아있는 치즈조각이 놓여 있는 칸의 개수를 구하는 프로그램을 작성하시오.

입력:

첫째 줄에는 사각형 모양 판의 세로와 가로의 길이가 양의 정수로 주어진다. 세로와 가로의 길이는 최대 100이다. 판의 각 가로줄의 모양이 윗 줄부터 차례로 둘째 줄부터 마지막 줄까지 주어진다. 치즈가 없는 칸은 0, 치즈가 있는 칸은 1로 주어지며 각 숫자 사이에는 빈칸이 하나씩 있다.

출력:

첫째 줄에는 치즈가 모두 녹아서 없어지는 데 걸리는 시간을 출력하고, 둘째 줄에는 모두 녹기 한 시간 전에 남아있는 치즈조각이 놓여 있는 칸의 개수를 출력한다.

풀이방법:

 일반적인 bfs와 다르게 이 치즈 문제에서는 '치즈 안에 빈 공간이 있는 경우에는 녹지 않는다' 라는 조건이 있기 때문에, 이를 신경써야 한다. 따라서 치즈를 기준으로 bfs를 하는 것이 아니라 공기를 기준으로 bfs를 수행하며 치즈를 만난 경우에 탐색을 종료하고 기록하는 방식으로 한다.

 0,0은 항상 공기이기 때문에(판의 가장자리) 이 점으로부터 시작해서 bfs를 수행하고, 모든 탐색을 마친 뒤에 한 번에 치즈를 녹이도록 한다. 이를 치즈가 모두 녹을 때까지 반복한다.

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
from collections import deque
import sys
 
#input = sys.stdin.readline
 
dx = [0,1,0,-1]
dy = [1,0,-1,0]
 
def bfs(count):
    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 and not visited[nx][ny]:
                visited[nx][ny] = 1
                if cheese[nx][ny]==1:
                    cheese[nx][ny] = -1
                    count-=1
                else:
                    queue.append((nx,ny))
    return count
 
def melt():
    for i in range(N):
        for j in range(M):
            if cheese[i][j] == -1:
                cheese[i][j] = 0
 
N,M = map(int,input().split())
cheese = []
count = 0
for _ in range(N):
    sub_cheese = list(map(int,input().split()))
    count += sum(sub_cheese)
    cheese.append(sub_cheese)
    
time = 0
answer = count
queue = deque()
while count:
    visited = [[0 for _ in range(M)] for _ in range(N)]
    queue.append((0,0))
    visited[0][0= 1
    count = bfs(count)
    
    if count:
        answer = count
        
    time+=1
    melt()
    
print(time)
print(answer)
cs

문제링크:

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

 

2636번: 치즈

첫째 줄에는 사각형 모양 판의 세로와 가로의 길이가 양의 정수로 주어진다. 세로와 가로의 길이는 최대 100이다. 판의 각 가로줄의 모양이 윗 줄부터 차례로 둘째 줄부터 마지막 줄까지 주어진

www.acmicpc.net

 

728x90
반응형

'Algorithm > Python' 카테고리의 다른 글

[BOJ]17406. 배열 돌리기 4  (0) 2021.09.08
[BOJ]2638. 치즈  (0) 2021.09.06
[BOJ] 11054. 가장 긴 바이토닉 부분 수열  (0) 2021.09.02
[BOJ]2565. 전깃줄  (0) 2021.09.01
[BOJ]2042. 구간 합 구하기  (0) 2021.08.31
728x90
반응형

문제:

수열 S가 어떤 수 Sk를 기준으로 S1 < S2 < ... Sk-1 < Sk > Sk+1 > ... SN-1 > SN을 만족한다면, 그 수열을 바이토닉 수열이라고 한다.

예를 들어, {10, 20, 30, 25, 20}과 {10, 20, 30, 40}, {50, 40, 25, 10} 은 바이토닉 수열이지만,  {1, 2, 3, 2, 1, 2, 3, 2, 1}과 {10, 20, 30, 40, 20, 30} 은 바이토닉 수열이 아니다.

수열 A가 주어졌을 때, 그 수열의 부분 수열 중 바이토닉 수열이면서 가장 긴 수열의 길이를 구하는 프로그램을 작성하시오.

입력:

첫째 줄에 수열 A의 크기 N이 주어지고, 둘째 줄에는 수열 A를 이루고 있는 Ai가 주어진다. (1 ≤ N ≤ 1,000, 1 ≤ Ai ≤ 1,000)

출력:

첫째 줄에 수열 A의 부분 수열 중에서 가장 긴 바이토닉 수열의 길이를 출력한다.

풀이방법:

 두 개의 LIS(가장 긴 증가하는 부분 수열)을 사용해서 풀면 된다. 한 LIS는 앞에서부터, 다른 LIS는 뒤에서부터 수행한다. 수행하면서 각 위치까지의 LIS의 길이를 저장해둔다.

두 배열(dp, dp2)에 LIS의 길이를 저장했으므로 이 둘을 zip으로 같이 탐색하면서 합이 가장 큰 경우를 답으로 출력하도록 한다. 즉, 이 말은 기준이 Sk를 기준으로 왼쪽과 오른쪽의 길이의 합을 더하는 것과 같으며, Sk는 최종적으로 두 번 더해지기 때문에 -1을 뺀 값이 정답이 된다.

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
31
32
33
34
35
36
37
import bisect
 
= int(input())
numbers = list(map(int,input().split()))
 
dp = []
seq = []
for i, n in enumerate(numbers):
    if not len(seq):
        seq.append(n)
    else:
        if seq[-1< n:
            seq.append(n)
        else:
            idx = bisect.bisect_left(seq,n)
            seq[idx] = n
    dp.append(len(seq))
    
dp2 = []
seq = []
numbers.reverse()
for i, n in enumerate(numbers):
    if not len(seq):
        seq.append(n)
    else:
        if seq[-1< n:
            seq.append(n)
        else:
            idx = bisect.bisect_left(seq,n)
            seq[idx] = n
    dp2.append(len(seq))
dp2.reverse()
 
answer = 0
for i,v in zip(dp,dp2):
    answer = max(answer,i+v)
print(answer-1)
cs

문제링크:

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

 

11054번: 가장 긴 바이토닉 부분 수열

첫째 줄에 수열 A의 크기 N이 주어지고, 둘째 줄에는 수열 A를 이루고 있는 Ai가 주어진다. (1 ≤ N ≤ 1,000, 1 ≤ Ai ≤ 1,000)

www.acmicpc.net

 

728x90
반응형

'Algorithm > Python' 카테고리의 다른 글

[BOJ]2638. 치즈  (0) 2021.09.06
[BOJ]2636. 치즈  (0) 2021.09.03
[BOJ]2565. 전깃줄  (0) 2021.09.01
[BOJ]2042. 구간 합 구하기  (0) 2021.08.31
[BOJ]2573. 빙산  (0) 2021.08.30
728x90
반응형

문제:

두 전봇대 A와 B 사이에 하나 둘씩 전깃줄을 추가하다 보니 전깃줄이 서로 교차하는 경우가 발생하였다. 합선의 위험이 있어 이들 중 몇 개의 전깃줄을 없애 전깃줄이 교차하지 않도록 만들려고 한다.

예를 들어, < 그림 1 >과 같이 전깃줄이 연결되어 있는 경우 A의 1번 위치와 B의 8번 위치를 잇는 전깃줄, A의 3번 위치와 B의 9번 위치를 잇는 전깃줄, A의 4번 위치와 B의 1번 위치를 잇는 전깃줄을 없애면 남아있는 모든 전깃줄이 서로 교차하지 않게 된다.

전깃줄이 전봇대에 연결되는 위치는 전봇대 위에서부터 차례대로 번호가 매겨진다. 전깃줄의 개수와 전깃줄들이 두 전봇대에 연결되는 위치의 번호가 주어질 때, 남아있는 모든 전깃줄이 서로 교차하지 않게 하기 위해 없애야 하는 전깃줄의 최소 개수를 구하는 프로그램을 작성하시오.

입력:

첫째 줄에는 두 전봇대 사이의 전깃줄의 개수가 주어진다. 전깃줄의 개수는 100 이하의 자연수이다. 둘째 줄부터 한 줄에 하나씩 전깃줄이 A전봇대와 연결되는 위치의 번호와 B전봇대와 연결되는 위치의 번호가 차례로 주어진다. 위치의 번호는 500 이하의 자연수이고, 같은 위치에 두 개 이상의 전깃줄이 연결될 수 없다.

출력:

첫째 줄에 남아있는 모든 전깃줄이 서로 교차하지 않게 하기 위해 없애야 하는 전깃줄의 최소 개수를 출력한다.

풀이방법:

 A, B를 쌍으로 저장한 뒤에 A를 기준으로 정렬한다. 그리고 B 값들에 대해 가장 긴 증가하는 부분 수열을 찾으면 가장 적게 제거하고 전깃줄이 서로 교차하지 않게 만들 수 있다.

 가장 긴 증가하는 부분 수열을 찾는 방법은 많지만 이분 탐색을 사용한 방법(N*log(N))을 통해서 찾고, 전체 길이에서 답을 구했다.

참조 링크 : https://seungkwan.tistory.com/8

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import bisect
 
= int(input())
e_line = []
for _ in range(N):
    A,B = map(int,input().split())
    e_line.append((A,B))
e_line = sorted(e_line)
 
dp = []
for A,B in e_line:
    #breakpoint()
    if not len(dp):
        dp.append(B)
    else:
        if dp[-1< B:
            dp.append(B)
        else:
            idx = bisect.bisect_left(dp,B)
            dp[idx] = B
print(N-len(dp))
cs

문제링크:

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

 

2565번: 전깃줄

첫째 줄에는 두 전봇대 사이의 전깃줄의 개수가 주어진다. 전깃줄의 개수는 100 이하의 자연수이다. 둘째 줄부터 한 줄에 하나씩 전깃줄이 A전봇대와 연결되는 위치의 번호와 B전봇대와 연결되는

www.acmicpc.net

 

728x90
반응형

'Algorithm > Python' 카테고리의 다른 글

[BOJ]2636. 치즈  (0) 2021.09.03
[BOJ] 11054. 가장 긴 바이토닉 부분 수열  (0) 2021.09.02
[BOJ]2042. 구간 합 구하기  (0) 2021.08.31
[BOJ]2573. 빙산  (0) 2021.08.30
[BOJ]10942. 팰린드롬?  (0) 2021.08.26
728x90
반응형

문제:

어떤 N개의 수가 주어져 있다. 그런데 중간에 수의 변경이 빈번히 일어나고 그 중간에 어떤 부분의 합을 구하려 한다. 만약에 1,2,3,4,5 라는 수가 있고, 3번째 수를 6으로 바꾸고 2번째부터 5번째까지 합을 구하라고 한다면 17을 출력하면 되는 것이다. 그리고 그 상태에서 다섯 번째 수를 2로 바꾸고 3번째부터 5번째까지 합을 구하라고 한다면 12가 될 것이다.

입력:

첫째 줄에 수의 개수 N(1 ≤ N ≤ 1,000,000)과 M(1 ≤ M ≤ 10,000), K(1 ≤ K ≤ 10,000) 가 주어진다. M은 수의 변경이 일어나는 횟수이고, K는 구간의 합을 구하는 횟수이다. 그리고 둘째 줄부터 N+1번째 줄까지 N개의 수가 주어진다. 그리고 N+2번째 줄부터 N+M+K+1번째 줄까지 세 개의 정수 a, b, c가 주어지는데, a가 1인 경우 b(1 ≤ b ≤ N)번째 수를 c로 바꾸고 a가 2인 경우에는 b(1 ≤ b ≤ N)번째 수부터 c(b ≤ c ≤ N)번째 수까지의 합을 구하여 출력하면 된다.

입력으로 주어지는 모든 수는 -263보다 크거나 같고, 263-1보다 작거나 같은 정수이다.

출력:

첫째 줄부터 K줄에 걸쳐 구한 구간의 합을 출력한다. 단, 정답은 -263보다 크거나 같고, 263-1보다 작거나 같은 정수이다.

풀이방법:

 세그먼트 트리를 사용해서 푸는 문제다. 세그먼트 트리에 대해서는 추후 자세하게 설명할 예정이다.

우선 현재 가지고 있는 노트의 갯수(N)를 기준으로 트리를 구성한다. 그 다음에 가진 값으로 트리를 채우게 되는데 가장 밑의 leaf는 각 값으로 구성되며, 부모 노드로 올라갈수록 leaf 노드들의 합으로 구성된다.

 change를 하는 경우에는 leaf 만을 바꾸는 것이 아니라 상위 노드들도 전부 바꿔야 하고, 부분합을 구하기 위해서는 반으로 나눠 탐색하며 구간에 해당하는 노드 값을 들고 와서 더해주면 된다.

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import math
import sys
input = sys.stdin.readline
N, M, K = map(int,input().split())
segment_tree = [0]*(pow(2,math.ceil(math.log(N,2))+1)-1)
numbers = [int(input()) for _ in range(N)]
 
def init(node, start, end):
    if start == end:
        segment_tree[node] = numbers[start]
        return segment_tree[node]
    else:
        segment_tree[node] = init(node*2,start,(start+end)//2+ init(node*2+1, (start+end)//2+1, end)
        return segment_tree[node]
    
def change(node, start, end, idx, diff):
    if idx < start or idx > end:
        return 
    segment_tree[node] += diff
    if start != end:
        change(node*2, start, (start+end)//2, idx, diff)
        change(node*2+1, (start+end)//2+1, end, idx, diff)
 
def subsum(node, start, end, left, right):
    if left > end or right < start:
        return 0
    
    if left <= start and end <= right:
        return segment_tree[node]
    
    return subsum(node*2, start, (start+end)//2, left, right)+ subsum(node*2+1, (start+end)//2+1, end, left, right)
    
    
init(1,0,N-1)
 
for _ in range(M+K):
    a, b, c = map(int,input().split())
    if a==1:
        b -= 1
        diff = c - numbers[b]
        numbers[b] = c
        change(1,0,N-1,b,diff)
    else:
        print(subsum(1,0,N-1,b-1,c-1))
cs

문제링크:

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

 

2042번: 구간 합 구하기

첫째 줄에 수의 개수 N(1 ≤ N ≤ 1,000,000)과 M(1 ≤ M ≤ 10,000), K(1 ≤ K ≤ 10,000) 가 주어진다. M은 수의 변경이 일어나는 횟수이고, K는 구간의 합을 구하는 횟수이다. 그리고 둘째 줄부터 N+1번째 줄

www.acmicpc.net

 

728x90
반응형

'Algorithm > Python' 카테고리의 다른 글

[BOJ] 11054. 가장 긴 바이토닉 부분 수열  (0) 2021.09.02
[BOJ]2565. 전깃줄  (0) 2021.09.01
[BOJ]2573. 빙산  (0) 2021.08.30
[BOJ]10942. 팰린드롬?  (0) 2021.08.26
[BOJ]1963. 소수경로  (0) 2021.08.24
728x90
반응형

문제:

지구 온난화로 인하여 북극의 빙산이 녹고 있다. 빙산을 그림 1과 같이 2차원 배열에 표시한다고 하자. 빙산의 각 부분별 높이 정보는 배열의 각 칸에 양의 정수로 저장된다. 빙산 이외의 바다에 해당되는 칸에는 0이 저장된다. 그림 1에서 빈칸은 모두 0으로 채워져 있다고 생각한다.

그림 1. 행의 개수가 5이고 열의 개수가 7인 2차원 배열에 저장된 빙산의 높이 정보

빙산의 높이는 바닷물에 많이 접해있는 부분에서 더 빨리 줄어들기 때문에, 배열에서 빙산의 각 부분에 해당되는 칸에 있는 높이는 일년마다 그 칸에 동서남북 네 방향으로 붙어있는 0이 저장된 칸의 개수만큼 줄어든다. 단, 각 칸에 저장된 높이는 0보다 더 줄어들지 않는다. 바닷물은 호수처럼 빙산에 둘러싸여 있을 수도 있다. 따라서 그림 1의 빙산은 일년후에 그림 2와 같이 변형된다.

그림 3은 그림 1의 빙산이 2년 후에 변한 모습을 보여준다. 2차원 배열에서 동서남북 방향으로 붙어있는 칸들은 서로 연결되어 있다고 말한다. 따라서 그림 2의 빙산은 한 덩어리이지만, 그림 3의 빙산은 세 덩어리로 분리되어 있다.

한 덩어리의 빙산이 주어질 때, 이 빙산이 두 덩어리 이상으로 분리되는 최초의 시간(년)을 구하는 프로그램을 작성하시오. 그림 1의 빙산에 대해서는 2가 답이다. 만일 전부 다 녹을 때까지 두 덩어리 이상으로 분리되지 않으면 프로그램은 0을 출력한다.

입력:

첫 줄에는 이차원 배열의 행의 개수와 열의 개수를 나타내는 두 정수 N과 M이 한 개의 빈칸을 사이에 두고 주어진다. N과 M은 3 이상 300 이하이다. 그 다음 N개의 줄에는 각 줄마다 배열의 각 행을 나타내는 M개의 정수가 한 개의 빈 칸을 사이에 두고 주어진다. 각 칸에 들어가는 값은 0 이상 10 이하이다. 배열에서 빙산이 차지하는 칸의 개수, 즉, 1 이상의 정수가 들어가는 칸의 개수는 10,000 개 이하이다. 배열의 첫 번째 행과 열, 마지막 행과 열에는 항상 0으로 채워진다.

출력:

첫 줄에 빙산이 분리되는 최초의 시간(년)을 출력한다. 만일 빙산이 다 녹을 때까지 분리되지 않으면 0을 출력한다.

풀이방법:

bfs를 사용해서 빙산을 녹이면서 덩어리가 2개가 되는 순간 그 때의 year 값을 출력하면 된다. 처음 가정으로는 한 덩어리의 빙산이기 때문에 빙산을 발견하면 그 점으로부터 bfs를 수행하면 된다. 빙산으로부터 4방향을 보고 나중에 한 번에 녹여야 하기 때문에 바로 녹이지 않고, 나중에 한 번에 녹이도록 한다.

만약 bfs를 두 번 탐색하는 경우에는 2개의 빙산이 있는 경우이기 때문에 더이상 진행하지 않도록 한다.

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
from collections import deque
import sys
 
#input = sys.stdin.readline
 
dx = [0,1,0,-1]
dy = [1,0,-1,0]
 
def check():
    visited = [[0 for _ in range(M)] for _ in range(N)]
    group_cnt = 0
    melting_queue = []
    for i in range(1,N-1):
        for j in range(1,M-1):
            if ice_mountain[i][j] and not visited[i][j]:
                group_cnt+=1
                d = deque([(i,j)])
                visited[i][j] = 1
                while d:
                    x,y = d.popleft()
                    melt_cnt = 0
                    for k in range(4):
                        nx = x + dx[k]
                        ny = y + dy[k]
                        if 0<= nx < N and 0 <=ny < M and not visited[nx][ny]:
                            if ice_mountain[nx][ny]:
                                d.append((nx,ny))
                                visited[nx][ny] = 1
                            else:
                                melt_cnt +=1
                    if melt_cnt:
                        melting_queue.append(((x,y),melt_cnt))
                        
    return melting_queue,group_cnt
                    
 
N,M = map(int,input().split())
ice_mountain = []
for i in range(N):
    ice_mountain.append(list(map(int,input().split())))
    
year = 0
while True:
    melting_queue, cnt = check()
    if not cnt:
        year = 0
        break
    elif cnt >= 2:
        break
    for i,dc in melting_queue:
        x,y = i
        ice_mountain[x][y] = max(ice_mountain[x][y]-dc,0)
    year+=1
print(year)
cs

문제링크:

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

 

2573번: 빙산

첫 줄에는 이차원 배열의 행의 개수와 열의 개수를 나타내는 두 정수 N과 M이 한 개의 빈칸을 사이에 두고 주어진다. N과 M은 3 이상 300 이하이다. 그 다음 N개의 줄에는 각 줄마다 배열의 각 행을

www.acmicpc.net

 

728x90
반응형

'Algorithm > Python' 카테고리의 다른 글

[BOJ]2565. 전깃줄  (0) 2021.09.01
[BOJ]2042. 구간 합 구하기  (0) 2021.08.31
[BOJ]10942. 팰린드롬?  (0) 2021.08.26
[BOJ]1963. 소수경로  (0) 2021.08.24
[BOJ]1074. Z  (0) 2021.08.12
728x90
반응형

문제:

명우는 홍준이와 함께 팰린드롬 놀이를 해보려고 한다.

먼저, 홍준이는 자연수 N개를 칠판에 적는다. 그 다음, 명우에게 질문을 총 M번 한다.

각 질문은 두 정수 S와 E(1 ≤ S ≤ E ≤ N)로 나타낼 수 있으며, S번째 수부터 E번째 까지 수가 팰린드롬을 이루는지를 물어보며, 명우는 각 질문에 대해 팰린드롬이다 또는 아니다를 말해야 한다.

예를 들어, 홍준이가 칠판에 적은 수가 1, 2, 1, 3, 1, 2, 1라고 하자.

  • S = 1, E = 3인 경우 1, 2, 1은 팰린드롬이다.
  • S = 2, E = 5인 경우 2, 1, 3, 1은 팰린드롬이 아니다.
  • S = 3, E = 3인 경우 1은 팰린드롬이다.
  • S = 5, E = 7인 경우 1, 2, 1은 팰린드롬이다.

자연수 N개와 질문 M개가 모두 주어졌을 때, 명우의 대답을 구하는 프로그램을 작성하시오.

입력:

첫째 줄에 수열의 크기 N (1 ≤ N ≤ 2,000)이 주어진다.

둘째 줄에는 홍준이가 칠판에 적은 수 N개가 순서대로 주어진다. 칠판에 적은 수는 100,000보다 작거나 같은 자연수이다.

셋째 줄에는 홍준이가 한 질문의 개수 M (1 ≤ M ≤ 1,000,000)이 주어진다.

넷째 줄부터 M개의 줄에는 홍준이가 명우에게 한 질문 S와 E가 한 줄에 하나씩 주어진다.

출력:

총 M개의 줄에 걸쳐 홍준이의 질문에 대한 명우의 답을 입력으로 주어진 순서에 따라서 출력한다. 팰린드롬인 경우에는 1, 아닌 경우에는 0을 출력한다.

풀이방법:

 "팰린드롬인 수열이 있다면 양쪽 끝에 같은 수를 붙이면 그 수열도 팰린드롬이 된다" 라는 아이디어를 통해서 풀 수 있는 문제다.

 따라서 dp 테이블을 다음과 같이 구성한다.

 

- dp[i][j] -> 1 if i~j의 수열이 팰린드롬

- dp[i][j] -> 0 if i~j의 수열이 팰린드롬이 아님

 

초기 dp 테이블 구성을 위해 1개 혹은 2개로 이루어진 팰린드롬만 따로 확인하여 구성하도록 한다. 나머지 값들에 대해서는 2중 for를 사용해서 양 끝 인덱스를 할당하고, 그 값이 같으며 그 속안의 dp 값이 1이라면(팰린드롬이라면) 그 수열도 팰린드롬이기 때문에 1로 바꿔주도록한다.

 위 과정을 통해 모든 dp 값을 최신화했다면, M을 통해 명령어를 받아 그 dp 테이블 값을 출력하도록 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import sys
 
input = sys.stdin.readline
 
= int(input())
numbers = list(map(int,input().split()))
dp = [[0 for _ in range(N)] for _ in range(N)]
 
for i in range(N):
    dp[i][i] = 1
for i in range(N-1):
    if numbers[i]==numbers[i+1]:
        dp[i][i+1= 1
        
for i in range(2,N):
    for j in range(N-i):
        k = j+i
        if numbers[j]==numbers[k] and dp[j+1][k-1]:
            dp[j][k] = 1
= int(input())
for _ in range(M):
    S, E = map(int,input().split())
    print(dp[S-1][E-1])
cs

문제링크:

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

 

10942번: 팰린드롬?

총 M개의 줄에 걸쳐 홍준이의 질문에 대한 명우의 답을 입력으로 주어진 순서에 따라서 출력한다. 팰린드롬인 경우에는 1, 아닌 경우에는 0을 출력한다.

www.acmicpc.net

 

728x90
반응형

'Algorithm > Python' 카테고리의 다른 글

[BOJ]2042. 구간 합 구하기  (0) 2021.08.31
[BOJ]2573. 빙산  (0) 2021.08.30
[BOJ]1963. 소수경로  (0) 2021.08.24
[BOJ]1074. Z  (0) 2021.08.12
[BOJ]2108. 통계학  (0) 2021.08.05
728x90
반응형

문제:

소수를 유난히도 좋아하는 창영이는 게임 아이디 비밀번호를 4자리 ‘소수’로 정해놓았다. 어느 날 창영이는 친한 친구와 대화를 나누었는데:

  • “이제 슬슬 비번 바꿀 때도 됐잖아”
  • “응 지금은 1033으로 해놨는데... 다음 소수를 무엇으로 할지 고민중이야"
  • “그럼 8179로 해”
  • “흠... 생각 좀 해볼게. 이 게임은 좀 이상해서 비밀번호를 한 번에 한 자리 밖에 못 바꾼단 말이야. 예를 들어 내가 첫 자리만 바꾸면 8033이 되니까 소수가 아니잖아. 여러 단계를 거쳐야 만들 수 있을 것 같은데... 예를 들면... 1033 1733 3733 3739 3779 8779 8179처럼 말이야.”
  • “흠...역시 소수에 미쳤군. 그럼 아예 프로그램을 짜지 그래. 네 자리 소수 두 개를 입력받아서 바꾸는데 몇 단계나 필요한지 계산하게 말야.”
  • “귀찮아”

그렇다. 그래서 여러분이 이 문제를 풀게 되었다. 입력은 항상 네 자리 소수만(1000 이상) 주어진다고 가정하자. 주어진 두 소수 A에서 B로 바꾸는 과정에서도 항상 네 자리 소수임을 유지해야 하고, ‘네 자리 수’라 하였기 때문에 0039 와 같은 1000 미만의 비밀번호는 허용되지 않는다.

입력:

첫 줄에 test case의 수 T가 주어진다. 다음 T줄에 걸쳐 각 줄에 1쌍씩 네 자리 소수가 주어진다.

출력:

각 test case에 대해 두 소수 사이의 변환에 필요한 최소 회수를 출력한다. 불가능한 경우 Impossible을 출력한다.

풀이방법:

 소수를 찾기 위한 에라토스테네스의 체와 그리고 한 소수로부터 다른 소수로 이동하기 위한 bfs를 사용하는 문제다.

우선 네 자리 수인 모든 소수를 찾기 위해서 에라토스테네스의 체를 사용한다. 에라토스테네스의 체를 1부터 10000까지 적용을 한 뒤에 filter를 사용해 1000보다 큰 수들만 남기도록 한다.

 네 자리 소수를 모두 구한 뒤에는 bfs를 사용해서 기준이 되는 숫자와 네 자리 소수를 모두 비교해서 하나만 다른 경우에만 새 queue에 넣는 방식으로 진행한다. 이 때 중복 방문을 피하기 위해서 visited 배열을 사용한다. 만약 목적지 소수를 발견하면 bfs를 종료하고 answer를 출력하며, 만약 모든 소수를 방문해도 도달하지 못했다면 Impossible을 출력하게 한다.

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
from collections import deque
import math
 
def check_sosu(s):
    for i in range(2,int(math.sqrt(s))+1):
        if not s%i:
            return 0
    return 1
 
def sosu():
    sosu_list = list(range(10001))
    sosu_list[1= 0
    for s in sosu_list:
        if sosu_list[s] and check_sosu(s):
            for j in range(s+s,10001,s):
                sosu_list[j]=0
    return list(set(sosu_list))
 
def change(a,b):
    count = 0
    for i,j in zip(str(a),str(b)):
        if i==j:
            count+=1
    if count==3:
        return 1
    else:
        return 0
 
= int(input())
sosu_list = sosu()
sosu_list = sorted(list(filter(lambda x: x >= 1000, sosu_list)))
 
for _ in range(T):
    start, end = map(int,input().split())
    visited = [0]*len(sosu_list)
    visited[sosu_list.index(start)]=1
    if start==end:
        print(0)
        continue
    queue = deque([start])
    answer = 0
    possible = False
    while not possible and queue:
        tmp = deque([])
        for q in queue:
            if q==end:
                possible = True
                break
            for i,s in enumerate(sosu_list):
                if not visited[i]:
                    if change(q,s):
                        tmp.append(s)
                        visited[i] = 1
        else:
            queue = tmp
            answer+=1
    if possible:
        print(answer)
    else:
        print("Impossible")
cs

문제링크:

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

 

1963번: 소수 경로

소수를 유난히도 좋아하는 창영이는 게임 아이디 비밀번호를 4자리 ‘소수’로 정해놓았다. 어느 날 창영이는 친한 친구와 대화를 나누었는데: “이제 슬슬 비번 바꿀 때도 됐잖아” “응 지금

www.acmicpc.net

 

728x90
반응형

'Algorithm > Python' 카테고리의 다른 글

[BOJ]2573. 빙산  (0) 2021.08.30
[BOJ]10942. 팰린드롬?  (0) 2021.08.26
[BOJ]1074. Z  (0) 2021.08.12
[BOJ]2108. 통계학  (0) 2021.08.05
[BOJ]2206. 벽 부수고 이동하기  (0) 2021.08.03
728x90
반응형

문제:

한수는 크기가 2N × 2N인 2차원 배열을 Z모양으로 탐색하려고 한다. 예를 들어, 2×2배열을 왼쪽 위칸, 오른쪽 위칸, 왼쪽 아래칸, 오른쪽 아래칸 순서대로 방문하면 Z모양이다.

 

만약, N > 1이 라서 왼쪽 위에 있는 칸이 하나가 아니라면, 배열을 크기가 2N-1 × 2N-1로 4등분 한 후에 재귀적으로 순서대로 방문한다.

다음 예는 22 × 22 크기의 배열을 방문한 순서이다.

N이 주어졌을 때, r행 c열을 몇 번째로 방문하는지 출력하는 프로그램을 작성하시오.

다음은 N=3일 때의 예이다.

입력:

첫째 줄에 정수 N, r, c가 주어진다.

출력:

r행 c열을 몇 번째로 방문했는지 출력한다.

풀이방법:

시간 제한이 생각보다 많이 빡세기 때문에, 분할 정복을 사용하더라도 좀 더 효율적인 방법이 필요하다. 따라서 r, c 좌표를 통해서 해당 영역으로 찾아들어가는 방식을 사용하도록 한다.

모든 영역은 2^N-1 영역으로 4등분하며 순서대로 방문하기 때문에 r과 c가 이렇게 나눈 영역에서 어느 곳에 속하는지 알면 된다.

우선 나눠지는 순서대로 왼쪽 위를 0번째, 오른쪽 위를 1번째, 왼쪽 아래를 2번째, 오른쪽 아래를 3번째라고 하자

 1. 0번째 영역에 속하기 위해서는 r과 c가 모두 2^(N-1)보다 작아야 한다. 그리고 0번째 영역의 첫 숫자는 항상 0이기 때문에 시작 값에 대한 변화가 없다.

 2. 1번째 영역에 속하기 위해서는 r은 2^(N-1)보다 작으며, c는 커야 한다. 1번째 영역의 왼쪽 위 첫 숫자는 4^(N-1)*1에 해당한다. (총 숫자는 2^N*2^N= 4^N 개 있으며, 이를 사등분 하면 각 영역당 숫자는 4^(N-1)개 있다.)

 3. 2번째 영역에 속하기 위해서는 r은 2^(N-1)보다 크며, c는 작아야 한다. 첫 숫자는 4^(N-1)*2이다.

 4. 3번째 영역에 속하기 위해서는 r과 c가 모두 2^(N-1)보다 커야 한다. 첫 숫자는 4^(N-1)*3이다.

위 4개 비교를 통해서 각 영역에 들어가기 위해 r과 c를 2^(N-1)보다 크다면 그 값을 빼주고, N=1이 될 때까지 반복한다.

 

최종적으로는 r과 c는 0아니면 1에 해당하는 제일 작은 Z를 얻을 수 있고, 해당하는 영역의 숫자를 answer에 더해 출력해주면 된다.

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
N, r, c = map(int,input().split())
answer = 0 
while N > 1:
    divide = 2**(N-1)
    if r < divide: # 0번째
        if c < divide:
            pass
        else#1번째
            answer += 4**(N-1* 1
            c -= divide
    else:
        if c < divide: #2번째
            answer += 4**(N-1* 2
            r -= divide
        else#3번째
            answer += 4**(N-1* 3
            r -= divide
            c -= divide
    N -= 1
    
if r:
    if c:
        print(answer+3)
    else:
        print(answer+2)
else:
    if c:
        print(answer+1)
    else:
        print(answer)
cs

문제링크:

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

 

1074번: Z

한수는 크기가 2N × 2N인 2차원 배열을 Z모양으로 탐색하려고 한다. 예를 들어, 2×2배열을 왼쪽 위칸, 오른쪽 위칸, 왼쪽 아래칸, 오른쪽 아래칸 순서대로 방문하면 Z모양이다. 만약, N > 1이 라서

www.acmicpc.net

 

728x90
반응형

'Algorithm > Python' 카테고리의 다른 글

[BOJ]10942. 팰린드롬?  (0) 2021.08.26
[BOJ]1963. 소수경로  (0) 2021.08.24
[BOJ]2108. 통계학  (0) 2021.08.05
[BOJ]2206. 벽 부수고 이동하기  (0) 2021.08.03
[BOJ]1753. 최단경로  (0) 2021.07.29
728x90
반응형

문제:

수를 처리하는 것은 통계학에서 상당히 중요한 일이다. 통계학에서 N개의 수를 대표하는 기본 통계값에는 다음과 같은 것들이 있다. 단, N은 홀수라고 가정하자.

  1. 산술평균 : N개의 수들의 합을 N으로 나눈 값
  2. 중앙값 : N개의 수들을 증가하는 순서로 나열했을 경우 그 중앙에 위치하는 값
  3. 최빈값 : N개의 수들 중 가장 많이 나타나는 값
  4. 범위 : N개의 수들 중 최댓값과 최솟값의 차이

N개의 수가 주어졌을 때, 네 가지 기본 통계값을 구하는 프로그램을 작성하시오.

입력:

첫째 줄에 수의 개수 N(1 ≤ N ≤ 500,000)이 주어진다. 단, N은 홀수이다. 그 다음 N개의 줄에는 정수들이 주어진다. 입력되는 정수의 절댓값은 4,000을 넘지 않는다.

출력:

첫째 줄에는 산술평균을 출력한다. 소수점 이하 첫째 자리에서 반올림한 값을 출력한다.

둘째 줄에는 중앙값을 출력한다.

셋째 줄에는 최빈값을 출력한다. 여러 개 있을 때에는 최빈값 중 두 번째로 작은 값을 출력한다.

넷째 줄에는 범위를 출력한다.

풀이방법:

1. 산술평균 : sum 함수를 통해서 합계를 구하고 N으로 나눈 뒤 round 한다.

2. 중앙값 : 배열을 정렬하고, N//2의 인덱스 값을 출력한다. (항상 홀수 길이를 가지고 있기 때문에 가능)

3. 최빈값 : collections의 Counter를 사용해서 각 값의 출력 횟수를 구하고, most_common으로 빈도수로 정렬한다. 이 때, 최빈값이 여러 개 있는지 확인한 후 적절하게 출력하도록 한다.

4. 범위 : 배열의 최댓값에서 최솟값을 뺀다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import sys
input = sys.stdin.readline
= int(input())
numbers = []
for _ in range(N):
    numbers.append(int(input()))
    
print(round(sum(numbers)/N))
numbers.sort()
print(numbers[N//2])
from collections import Counter
if len(numbers)==1:
    print(numbers[0])
else:
    c = Counter(numbers)
    commons = c.most_common()
    if commons[0][1== commons[1][1]:
        print(commons[1][0])
    else:
        print(commons[0][0])
print(max(numbers)-min(numbers))
cs

문제링크:

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

 

2108번: 통계학

첫째 줄에 수의 개수 N(1 ≤ N ≤ 500,000)이 주어진다. 단, N은 홀수이다. 그 다음 N개의 줄에는 정수들이 주어진다. 입력되는 정수의 절댓값은 4,000을 넘지 않는다.

www.acmicpc.net

 

728x90
반응형

'Algorithm > Python' 카테고리의 다른 글

[BOJ]1963. 소수경로  (0) 2021.08.24
[BOJ]1074. Z  (0) 2021.08.12
[BOJ]2206. 벽 부수고 이동하기  (0) 2021.08.03
[BOJ]1753. 최단경로  (0) 2021.07.29
[BOJ]18870. 좌표 압축  (0) 2021.07.27

+ Recent posts