문제:

각각 부피가 A, B, C(1≤A, B, C≤200) 리터인 세 개의 물통이 있다. 처음에는 앞의 두 물통은 비어 있고, 세 번째 물통은 가득(C 리터) 차 있다. 이제 어떤 물통에 들어있는 물을 다른 물통으로 쏟아 부을 수 있는데, 이때에는 한 물통이 비거나, 다른 한 물통이 가득 찰 때까지 물을 부을 수 있다. 이 과정에서 손실되는 물은 없다고 가정한다.

이와 같은 과정을 거치다보면 세 번째 물통(용량이 C인)에 담겨있는 물의 양이 변할 수도 있다. 첫 번째 물통(용량이 A인)이 비어 있을 때, 세 번째 물통(용량이 C인)에 담겨있을 수 있는 물의 양을 모두 구해내는 프로그램을 작성하시오.

입력:

첫째 줄에 세 정수 A, B, C가 주어진다.

출력:

첫째 줄에 공백으로 구분하여 답을 출력한다. 각 용량은 오름차순으로 정렬한다.

풀이방법:

A, B를 담을 수 있는 물통들을 기준으로 하여 visited 배열을 만들고, BFS를 수행하도록 한다. visited의 가능한 갯수는 A와 B에 담을 수 있는 경우의 수와 같다. 처음은 비어있기 때문에, (0,0)으로부터 시작하도록 한다. 매 C는 가지고 있는 A, B 물의 양을 통해 구하도록 한다. 가지고 있는 A, B, C 물의 양을 통해 이동할 수 있는 모든 경우에 대해 조사하도록 한다. (A-> B, A-> C, B->C, B-> A, C-> A, C-> B)와 같은 총 6가지 case가 존재한다. 가능한 모든 경우에 대해 BFS를 수행하며 A의 물의 양이 0인 경우에 C의 값을 저장하도록 한다.

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
from collections import deque
 
A, B, C = map(int,input().split())
 
queue = deque()
queue.append((0,0))
visited = [[0 for _ in range(B+1)] for _ in range(A+1)]
visited[0][0= 1
 
answer = []
while queue:
    x,y = queue.popleft()
    z = C-x-y
    if x==0:
        answer.append(z)
    
    #A->B
    water = min(x,B-y)
    if not visited[x-water][y+water]:
        visited[x-water][y+water] = 1
        queue.append((x-water,y+water))
    
    #A->C
    water = min(x,C-z)
    if not visited[x-water][y]:
        visited[x-water][y] = 1
        queue.append((x-water,y))
        
    #B->C
    water = min(y,C-z)
    if not visited[x][y-water]:
        visited[x][y-water] = 1
        queue.append((x,y-water))
        
    #B->A
    water = min(y,A-x)
    if not visited[x+water][y-water]:
        visited[x+water][y-water] = 1
        queue.append((x+water,y-water))
        
    #C->A
    water = min(z,A-x)
    if not visited[x+water][y]:
        visited[x+water][y] = 1
        queue.append((x+water,y))
 
    #C->B
    water = min(z,B-y)
    if not visited[x][y+water]:
        visited[x][y+water] = 1
        queue.append((x,y+water))
    
print(*sorted(answer))
cs

문제링크:

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

 

2251번: 물통

각각 부피가 A, B, C(1≤A, B, C≤200) 리터인 세 개의 물통이 있다. 처음에는 앞의 두 물통은 비어 있고, 세 번째 물통은 가득(C 리터) 차 있다. 이제 어떤 물통에 들어있는 물을 다른 물통으로 쏟아 부

www.acmicpc.net

 

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

[BOJ]11058. 크리보드  (0) 2021.11.01
[BOJ]14391. 종이 조각  (0) 2021.10.29
[BOJ] 15988. 1, 2, 3 더하기  (0) 2021.10.25
[BOJ] 13023. ABCDE  (0) 2021.10.22
[BOJ]1339. 단어 수학  (0) 2021.10.21

문제:

BOJ 알고리즘 캠프에는 총 N명이 참가하고 있다. 사람들은 0번부터 N-1번으로 번호가 매겨져 있고, 일부 사람들은 친구이다.

오늘은 다음과 같은 친구 관계를 가진 사람 A, B, C, D, E가 존재하는지 구해보려고 한다.

  • A는 B와 친구다.
  • B는 C와 친구다.
  • C는 D와 친구다.
  • D는 E와 친구다.

위와 같은 친구 관계가 존재하는지 안하는지 구하는 프로그램을 작성하시오.

입력:

첫째 줄에 사람의 수 N (5 ≤ N ≤ 2000)과 친구 관계의 수 M (1 ≤ M ≤ 2000)이 주어진다.

둘째 줄부터 M개의 줄에는 정수 a와 b가 주어지며, a와 b가 친구라는 뜻이다. (0 ≤ a, b ≤ N-1, a ≠ b) 같은 친구 관계가 두 번 이상 주어지는 경우는 없다.

출력:

문제의 조건에 맞는 A, B, C, D, E가 존재하면 1을 없으면 0을 출력한다.

풀이방법:

 처음에는 문제를 조금 이해하는 것이 어려웠다. 주어진 모든 사람의 관계가 조건과 같이 구성되어야 하는줄 알았는데, 일부 사람들만 관계를 유지하면 된다. 따라서 N명의 사람들의 관계를 트리 형태로 구성했을 때, 하나의 노드로부터 깊이가 4인 경우가 있는지 확인하면 된다.

 따라서 처음에는 주어진 관계들을 양방향 그래프로 정리를 한다. 그 다음에는 각 노드로부터 dfs를 수행했을 때, 깊이가 4인 경우가 있는지 확인한다. 깊이가 4인 경우가 한 개라도 있으면 되기 때문에 찾았다면 탐색을 중지하고 1을 출력하며, 모든 노드로부터 탐색했는데 없다면 0을 출력하도록 한다.

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
def dfs(node, depth):
    global answer
    if depth==4:
        answer = 1
        return
    for f in friends[node]:
        if f in relationship:
            continue
        relationship.append(f)
        dfs(f,depth+1)
        relationship.pop()
 
N, M = map(int,input().split())
 
friends = [[] for _ in range(N)]
for _ in range(M):
    a, b = map(int, input().split())
    friends[a].append(b)
    friends[b].append(a)
 
answer = 0
for i in range(N):
    relationship = [i]
    dfs(i, 0)
    if answer:
        break
print(answer)
cs

문제링크:

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

 

13023번: ABCDE

문제의 조건에 맞는 A, B, C, D, E가 존재하면 1을 없으면 0을 출력한다.

www.acmicpc.net

 

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

[BOJ] 2251. 물통  (0) 2021.10.28
[BOJ] 15988. 1, 2, 3 더하기  (0) 2021.10.25
[BOJ]1339. 단어 수학  (0) 2021.10.21
[BOJ] 15658. 연산자 끼워넣기 (2)  (0) 2021.10.20
[BOJ] 17140. 이차원 배열과 연산  (0) 2021.10.19

문제:

세로 두 줄, 가로로 N개의 칸으로 이루어진 표가 있다. 첫째 줄의 각 칸에는 정수 1, 2, …, N이 차례대로 들어 있고 둘째 줄의 각 칸에는 1이상 N이하인 정수가 들어 있다. 첫째 줄에서 숫자를 적절히 뽑으면, 그 뽑힌 정수들이 이루는 집합과, 뽑힌 정수들의 바로 밑의 둘째 줄에 들어있는 정수들이 이루는 집합이 일치한다. 이러한 조건을 만족시키도록 정수들을 뽑되, 최대로 많이 뽑는 방법을 찾는 프로그램을 작성하시오. 예를 들어, N=7인 경우 아래와 같이 표가 주어졌다고 하자.

이 경우에는 첫째 줄에서 1, 3, 5를 뽑는 것이 답이다. 첫째 줄의 1, 3, 5밑에는 각각 3, 1, 5가 있으며 두 집합은 일치한다. 이때 집합의 크기는 3이다. 만약 첫째 줄에서 1과 3을 뽑으면, 이들 바로 밑에는 정수 3과 1이 있으므로 두 집합이 일치한다. 그러나, 이 경우에 뽑힌 정수의 개수는 최대가 아니므로 답이 될 수 없다.

입력:

첫째 줄에는 N(1≤N≤100)을 나타내는 정수 하나가 주어진다. 그 다음 줄부터는 표의 둘째 줄에 들어가는 정수들이 순서대로 한 줄에 하나씩 입력된다.

출력:

첫째 줄에 뽑힌 정수들의 개수를 출력하고, 그 다음 줄부터는 뽑힌 정수들을 작은 수부터 큰 수의 순서로 한 줄에 하나씩 출력한다.

풀이방법:

 뽑힌 정수들이 이루는 집학과 뽑힌 정수들의 바로 밑의 둘째 줄에 들어있는 정수들이 이루는 집합이 일치한다는 것은 그 해당 정수들로 사이클이 이뤄진다는 것과 동일하다. 즉, 이 문제는 숫자 배열들 중에서 가장 큰 사이클을 찾으면 된다.

 따라서 사이클을 찾기 위해 DFS를 사용하여 문제를 풀도록 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from collections import defaultdict
 
def dfs(now,start):
    visited[now] = 1
    
    for n in numbers[now]:
        if not visited[n]:
            dfs(n,start)
        elif visited[n] and n==start:
            answer.append(n)
 
= int(input())
numbers = defaultdict(list)
for i in range(1,N+1):
    numbers[i].append(int(input()))
    
answer = []
for i in range(1,N+1):
    visited = [0 for _ in range(N+1)]
    dfs(i,i)
    
print(len(answer))
for i in range(len(answer)):
    print(answer[i])  
cs

문제링크:

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

 

2668번: 숫자고르기

세로 두 줄, 가로로 N개의 칸으로 이루어진 표가 있다. 첫째 줄의 각 칸에는 정수 1, 2, …, N이 차례대로 들어 있고 둘째 줄의 각 칸에는 1이상 N이하인 정수가 들어 있다. 첫째 줄에서 숫자를 적절

www.acmicpc.net

 

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

[BOJ] 17140. 이차원 배열과 연산  (0) 2021.10.19
[BOJ]2659. 십자카드 문제  (0) 2021.10.18
[BOJ] 16918. 봄버맨  (0) 2021.10.14
[BOJ] 16236. 아기 상어  (0) 2021.10.13
[BOJ] 15683. 감시  (0) 2021.10.12

문제:

봄버맨은 크기가 R×C인 직사각형 격자판 위에서 살고 있다. 격자의 각 칸은 비어있거나 폭탄이 들어있다.

폭탄이 있는 칸은 3초가 지난 후에 폭발하고, 폭탄이 폭발한 이후에는 폭탄이 있던 칸이 파괴되어 빈 칸이 되며, 인접한 네 칸도 함께 파괴된다. 즉, 폭탄이 있던 칸이 (i, j)인 경우에 (i+1, j), (i-1, j), (i, j+1), (i, j-1)도 함께 파괴된다. 만약, 폭탄이 폭발했을 때, 인접한 칸에 폭탄이 있는 경우에는 인접한 폭탄은 폭발 없이 파괴된다. 따라서, 연쇄 반응은 없다.

봄버맨은 폭탄에 면역력을 가지고 있어서, 격자판의 모든 칸을 자유롭게 이동할 수 있다. 봄버맨은 다음과 같이 행동한다.

  • 가장 처음에 봄버맨은 일부 칸에 폭탄을 설치해 놓는다. 모든 폭탄이 설치된 시간은 같다.
  • 다음 1초 동안 봄버맨은 아무것도 하지 않는다.
  • 다음 1초 동안 폭탄이 설치되어 있지 않은 모든 칸에 폭탄을 설치한다. 즉, 모든 칸은 폭탄을 가지고 있게 된다. 폭탄은 모두 동시에 설치했다고 가정한다.
  • 1초가 지난 후에 3초 전에 설치된 폭탄이 모두 폭발한다.
  • 3과 4를 반복한다.

폭탄을 설치해놓은 초기 상태가 주어졌을 때, N초가 흐른 후의 격자판 상태를 구하려고 한다.

예를 들어, 초기 상태가 아래와 같은 경우를 보자.

1초가 지난 후에는 아무 일도 벌어지지 않기 때문에, 위와 같다고 볼 수 있다. 1초가 더 흐른 후에 격자판의 상태는 아래와 같아진다.

1초가 지난 후엔 가운데에 있는 폭탄이 폭발해 가운데 칸과 인접한 네 칸이 빈 칸이 된다.

입력:

첫째 줄에 R, C, N (1 ≤ R, C, N ≤ 200)이 주어진다. 둘째 줄부터 R개의 줄에 격자판의 초기 상태가 주어진다. 빈 칸은 '.'로, 폭탄은 'O'로 주어진다.

출력:

총 R개의 줄에 N초가 지난 후의 격자판 상태를 출력한다.

풀이방법:

 문제의 조건대로 폭탄을 설치하고 터트리는 과정을 반복하면 된다. 문제에서는 설치하는 과정, 폭발하는 과정이 1초씩 각각 수행되는 것으로 나타나지만 같은 while에서 수행하도록 한다.

 현재 지도에서 폭탄이 있는 위치를 찾아 좌표만을 저장한 후 빈 공간에 폭탄을 모두 채워 넣는다.( 따라서 매 짝수초마다 폭탄으로 가득찬 지도를 얻는다.) 그리고 폭탄을 설치하기 전에 찾았던 폭탄의 위치를 근거로만 폭탄을 제거하도록 한다.

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
dx = [-1,0,1,0]
dy = [0,1,0,-1]
 
def del_bomb(maps):
    while bombs:
        x,y= bombs.popleft()
        maps[x][y] = '.'
        for i in range(4):
            nx = x + dx[i]
            ny = y + dy[i]
            if 0<=nx<and 0<=ny<C:
                maps[nx][ny]='.'
def set_bomb(maps):
    for i in range(R):
        for j in range(C):
            if maps[i][j]=='.':
                maps[i][j] = 'O'
                
def find_bomb(maps):
    for i in range(R):
        for j in range(C):
            if maps[i][j]=='O':
                bombs.append((i,j))
 
from collections import deque
R, C, N = map(int,input().split())
maps = []
for _ in range(R):
    maps.append(list(input()))
    
time = 1
while time!=N:
    bombs = deque()
    find_bomb(maps)
    set_bomb(maps)
    time+=1
    if time==N:
        break
    del_bomb(maps)
    time+=1
        
 
for map_ in maps:
    print("".join(map_))
cs

문제링크:

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

 

16918번: 봄버맨

첫째 줄에 R, C, N (1 ≤ R, C, N ≤ 200)이 주어진다. 둘째 줄부터 R개의 줄에 격자판의 초기 상태가 주어진다. 빈 칸은 '.'로, 폭탄은 'O'로 주어진다.

www.acmicpc.net

 

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

[BOJ]2659. 십자카드 문제  (0) 2021.10.18
[BOJ] 2668. 숫자고르기  (0) 2021.10.15
[BOJ] 16236. 아기 상어  (0) 2021.10.13
[BOJ] 15683. 감시  (0) 2021.10.12
[BOJ] 14500. 테트로미노  (0) 2021.10.08

문제:

N×N 크기의 공간에 물고기 M마리와 아기 상어 1마리가 있다. 공간은 1×1 크기의 정사각형 칸으로 나누어져 있다. 한 칸에는 물고기가 최대 1마리 존재한다.

아기 상어와 물고기는 모두 크기를 가지고 있고, 이 크기는 자연수이다. 가장 처음에 아기 상어의 크기는 2이고, 아기 상어는 1초에 상하좌우로 인접한 한 칸씩 이동한다.

아기 상어는 자신의 크기보다 큰 물고기가 있는 칸은 지나갈 수 없고, 나머지 칸은 모두 지나갈 수 있다. 아기 상어는 자신의 크기보다 작은 물고기만 먹을 수 있다. 따라서, 크기가 같은 물고기는 먹을 수 없지만, 그 물고기가 있는 칸은 지나갈 수 있다.

아기 상어가 어디로 이동할지 결정하는 방법은 아래와 같다.

  • 더 이상 먹을 수 있는 물고기가 공간에 없다면 아기 상어는 엄마 상어에게 도움을 요청한다.
  • 먹을 수 있는 물고기가 1마리라면, 그 물고기를 먹으러 간다.
  • 먹을 수 있는 물고기가 1마리보다 많다면, 거리가 가장 가까운 물고기를 먹으러 간다.
    • 거리는 아기 상어가 있는 칸에서 물고기가 있는 칸으로 이동할 때, 지나야하는 칸의 개수의 최솟값이다.
    • 거리가 가까운 물고기가 많다면, 가장 위에 있는 물고기, 그러한 물고기가 여러마리라면, 가장 왼쪽에 있는 물고기를 먹는다.

아기 상어의 이동은 1초 걸리고, 물고기를 먹는데 걸리는 시간은 없다고 가정한다. 즉, 아기 상어가 먹을 수 있는 물고기가 있는 칸으로 이동했다면, 이동과 동시에 물고기를 먹는다. 물고기를 먹으면, 그 칸은 빈 칸이 된다.

아기 상어는 자신의 크기와 같은 수의 물고기를 먹을 때 마다 크기가 1 증가한다. 예를 들어, 크기가 2인 아기 상어는 물고기를 2마리 먹으면 크기가 3이 된다.

공간의 상태가 주어졌을 때, 아기 상어가 몇 초 동안 엄마 상어에게 도움을 요청하지 않고 물고기를 잡아먹을 수 있는지 구하는 프로그램을 작성하시오.

입력:

첫째 줄에 공간의 크기 N(2 ≤ N ≤ 20)이 주어진다.

둘째 줄부터 N개의 줄에 공간의 상태가 주어진다. 공간의 상태는 0, 1, 2, 3, 4, 5, 6, 9로 이루어져 있고, 아래와 같은 의미를 가진다.

  • 0: 빈 칸
  • 1, 2, 3, 4, 5, 6: 칸에 있는 물고기의 크기
  • 9: 아기 상어의 위치

아기 상어는 공간에 한 마리 있다.

출력:

첫째 줄에 아기 상어가 엄마 상어에게 도움을 요청하지 않고 물고기를 잡아먹을 수 있는 시간을 출력한다.

풀이방법:

 BFS를 통해 아기 상어가 먹을 수 있는 물고기를 찾은 후에 문제 조건에 맞게 정렬하여 하나씩 먹으면 된다.

무한 while을 사용하며 엄마 상어를 호출할 경우(탐색했지만 먹을 수 있는 물고기가 없는 경우)에만 빠져나올 수 있도록 한다. eat_fish함수를 통해 탐색하며 일반적인 bfs 알고리즘을 사용한다. 이 때, 빠른 탐색을 위해 좌표만을 저장하는 것이 아닌 distance도 구해서 먹을 수 있는 물고기를 찾는 조건을 한번의 sort로 찾을 수 있도록 한다.

 먹을 수 있는 물고기를 찾은 경우에는 maps를 최신화하고, 아기 상어의 size를 늘린다. 이 때, 아기 상어의 size가 커진 경우에는 count를 초기화 시키도록 한다. (2개 먹음 -> 성장 -> 다시 3개 먹음 -> 성장 -> ...)

 BFS 과정에서 찾은 distance를 시간에 더하도록 하며, 못 찾을 때 while을 나와 time을 출력한다.

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
61
dx = [-1,0,1,0]
dy = [0,1,0,-1]
 
def eat_fish(maps,i,j):
    queue = [(i,j,0)]
    visited = [[0 for _ in range(N)] for _ in range(N)]
    visited[i][j] = 1
    fish = []
    while queue:
        next_ = []
        for q in queue:
            x,y,count = q
            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]:
                        if 0<= maps[nx][ny] <= size:
                            if maps[nx][ny]!=0 and maps[nx][ny] < size:
                                fish.append((nx,ny,count+1))
                            next_.append((nx,ny,count+1))
                            visited[nx][ny] = 1
        queue = next_
    if fish:
        fish.sort(key=lambda x: (x[2],x[0],x[1]))
        return fish[0][0], fish[0][1],fish[0][2]
    else:
        return -1,-1,-1
            
= int(input())
 
maps = []
for _ in range(N):
    maps.append(list(map(int,input().split())))
    
ate  = maps.copy()
eat_count = 0
total_count = 0
time = 0
for i in range(N):
    for j in range(N):
        if maps[i][j]==9:
            x,y = i,j
            ate[x][y] = 0
        elif maps[i][j]:
            total_count+=1
 
size = 2
while True:
    nx,ny,d = eat_fish(maps,x,y)
    if nx==-1 and ny==-1:
        break
    else:
        maps[nx][ny] = 0
        time+=d
        eat_count+=1
    if eat_count==size:
        size+=1
        eat_count = 0
    x,y = nx,ny
print(time)
cs

문제링크:

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

 

16236번: 아기 상어

N×N 크기의 공간에 물고기 M마리와 아기 상어 1마리가 있다. 공간은 1×1 크기의 정사각형 칸으로 나누어져 있다. 한 칸에는 물고기가 최대 1마리 존재한다. 아기 상어와 물고기는 모두 크기를 가

www.acmicpc.net

 

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

[BOJ] 2668. 숫자고르기  (0) 2021.10.15
[BOJ] 16918. 봄버맨  (0) 2021.10.14
[BOJ] 15683. 감시  (0) 2021.10.12
[BOJ] 14500. 테트로미노  (0) 2021.10.08
[BOJ]2458. 키 순서  (0) 2021.10.07

문제:

1번부터 N번까지 번호가 붙여져 있는 학생들에 대하여 두 학생끼리 키를 비교한 결과의 일부가 주어져 있다. 단, N명의 학생들의 키는 모두 다르다고 가정한다. 예를 들어, 6명의 학생들에 대하여 6번만 키를 비교하였고, 그 결과가 다음과 같다고 하자.

  • 1번 학생의 키 < 5번 학생의 키
  • 3번 학생의 키 < 4번 학생의 키
  • 5번 학생의 키 < 4번 학생의 키
  • 4번 학생의 키 < 2번 학생의 키
  • 4번 학생의 키 < 6번 학생의 키
  • 5번 학생의 키 < 2번 학생의 키

이 비교 결과로부터 모든 학생 중에서 키가 가장 작은 학생부터 자신이 몇 번째인지 알 수 있는 학생들도 있고 그렇지 못한 학생들도 있다는 사실을 아래처럼 그림을 그려 쉽게 확인할 수 있다. a번 학생의 키가 b번 학생의 키보다 작다면, a에서 b로 화살표를 그려서 표현하였다. 

1번은 5번보다 키가 작고, 5번은 4번보다 작기 때문에, 1번은 4번보다 작게 된다. 그러면 1번, 3번, 5번은 모두 4번보다 작게 된다. 또한 4번은 2번과 6번보다 작기 때문에, 4번 학생은 자기보다 작은 학생이 3명이 있고, 자기보다 큰 학생이 2명이 있게 되어 자신의 키가 몇 번째인지 정확히 알 수 있다. 그러나 4번을 제외한 학생들은 자신의 키가 몇 번째인지 알 수 없다.

학생들의 키를 비교한 결과가 주어질 때, 자신의 키가 몇 번째인지 알 수 있는 학생들이 모두 몇 명인지 계산하여 출력하는 프로그램을 작성하시오.

입력:

첫째 줄에 학생들의 수 N (2 ≤ N ≤ 500)과 두 학생 키를 비교한 횟수 M (0 ≤ M ≤ N(N-1)/2)이 주어진다. 다음 M개의 각 줄에는 두 학생의 키를 비교한 결과를 나타내는 두 양의 정수 a와 b가 주어진다. 이는 번호가 a인 학생이 번호가 b인 학생보다 키가 작은 것을 의미한다. 

출력:

자신이 키가 몇 번째인지 알 수 있는 학생이 모두 몇 명인지를 출력한다. 

풀이방법:

 자신을 기준으로 다른 사람에게 도달할 수 있다. 즉, 비교를 할 수 있는 사람이 몇명인지 확인하도록 한다. 자신보다 큰 사람과 자신보다 작은 사람이 N-1명이면 자신의 키가 몇 번째인지 알 수 있다.

 따라서 플로이드 와샬을 사용해서 이 문제를 풀도록 한다. 플로이드 와샬은 모든 꼭짓점 쌍 간의 최단 경로의 길이를 알 수 있는 알고리즘인데, 이 문제에 알맞게 몇명과 비교를 할 수 있는지 여부로 수정하여 문제를 해결하도록 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
N, M = map(int,input().split())
graph = [[0 for _ in range(N)] for _ in range(N)]
for _ in range(M):
    a, b = map(int,input().split())
    graph[a-1][b-1= 1
 
for k in range(N):
    for i in range(N):
        for j in range(N):
            if graph[i][j] or (graph[i][k] and graph[k][j]):
                graph[i][j] = 1
                
answer = 0
for i in range(N):
    tmp = 0
    for j in range(N):
        tmp += graph[i][j] + graph[j][i]
    if tmp == N-1:
        answer+=1
print(answer)
cs

문제링크:

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

 

2458번: 키 순서

1번부터 N번까지 번호가 붙여져 있는 학생들에 대하여 두 학생끼리 키를 비교한 결과의 일부가 주어져 있다. 단, N명의 학생들의 키는 모두 다르다고 가정한다. 예를 들어, 6명의 학생들에 대하여

www.acmicpc.net

 

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

[BOJ] 15683. 감시  (0) 2021.10.12
[BOJ] 14500. 테트로미노  (0) 2021.10.08
[BOJ] 21608. 상어 초등학교  (0) 2021.10.06
[BOJ] 10157. 자리배정  (0) 2021.10.05
[BOJ] 1019. 책 페이지  (0) 2021.10.01

문제:

당신은 상범 빌딩에 갇히고 말았다. 여기서 탈출하는 가장 빠른 길은 무엇일까? 상범 빌딩은 각 변의 길이가 1인 정육면체(단위 정육면체)로 이루어져있다. 각 정육면체는 금으로 이루어져 있어 지나갈 수 없거나, 비어있어서 지나갈 수 있게 되어있다. 당신은 각 칸에서 인접한 6개의 칸(동,서,남,북,상,하)으로 1분의 시간을 들여 이동할 수 있다. 즉, 대각선으로 이동하는 것은 불가능하다. 그리고 상범 빌딩의 바깥면도 모두 금으로 막혀있어 출구를 통해서만 탈출할 수 있다.

당신은 상범 빌딩을 탈출할 수 있을까? 만약 그렇다면 얼마나 걸릴까?

입력:

입력은 여러 개의 테스트 케이스로 이루어지며, 각 테스트 케이스는 세 개의 정수 L, R, C로 시작한다. L(1 ≤ L ≤ 30)은 상범 빌딩의 층 수이다. R(1 ≤ R ≤ 30)과 C(1 ≤ C ≤ 30)는 상범 빌딩의 한 층의 행과 열의 개수를 나타낸다.

그 다음 각 줄이 C개의 문자로 이루어진 R개의 행이 L번 주어진다. 각 문자는 상범 빌딩의 한 칸을 나타낸다. 금으로 막혀있어 지나갈 수 없는 칸은 '#'으로 표현되고, 비어있는 칸은 '.'으로 표현된다. 당신의 시작 지점은 'S'로 표현되고, 탈출할 수 있는 출구는 'E'로 표현된다. 각 층 사이에는 빈 줄이 있으며, 입력의 끝은 L, R, C가 모두 0으로 표현된다. 시작 지점과 출구는 항상 하나만 있다.

출력:

각 빌딩에 대해 한 줄씩 답을 출력한다. 만약 당신이 탈출할 수 있다면 다음과 같이 출력한다.

Escaped in x minute(s).

여기서 x는 상범 빌딩을 탈출하는 데에 필요한 최단 시간이다.

만일 탈출이 불가능하다면, 다음과 같이 출력한다.

Trapped!

풀이방법:

 상하좌우로만 움직이는 일반 그래프 문제와 다르게 위, 아래의 개념이 추가된 문제다. 따라서 기존 2중 배열로 구성되던 visited 배열을 3중 배열로 바꿔서 풀도록 한다.

 첫 시작점을 찾은 뒤에 BFS를 통해 움직일 수 없을 때까지 계속 움직이고, 만약 목적지에 도달하면 그 때의 시간을 반환하고, 그렇지 못하면 0을 반환하게 한다.

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
def bfs(start, visited):
    queue = [start]
    visited[start[0]][start[1]][start[2]] = 1
    time = 1
    while queue:
        tmp = []
        for q in queue:
            z,x,y = q
            for i in range(6):
                nx = x + dx[i]
                ny = y + dy[i]
                nz = z + dz[i]
                if 0<= nx < R and 0<= ny < C and 0<= nz < L and not visited[nz][nx][ny] and (building[nz][nx][ny]=='.' or building[nz][nx][ny]=='E'):
                    if building[nz][nx][ny]=='E':
                        return time
                    visited[nz][nx][ny] = 1
                    tmp.append([nz,nx,ny])
        queue = tmp
        time+=1
    return 0
 
dx = [0,0,1,0,0,-1]
dy = [0,1,0,0,-1,0]
dz = [1,0,0,-1,0,0]
 
while True:
    L, R, C = map(int,input().split())
    if L==R==C==0:
        break
        
    building = []
    visited = [[[0 for _ in range(C)] for _ in range(R)] for _ in range(L)]
    for l in range(L):
        floor = []
        for r in range(R):
            tmp = list(input())
            if 'S' in tmp:
                start_point = [l,r,tmp.index('S')]
            floor.append(tmp)
        input()
        building.append(floor)
    time = bfs(start_point,visited)
    if time:
        print(f'Escaped in {time} minute(s).')
    else:
        print("Trapped!")
cs

문제링크:

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

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

[BOJ] 1019. 책 페이지  (0) 2021.10.01
[BOJ]3020. 개똥벌레  (0) 2021.09.30
[BOJ]12904. A와 B  (0) 2021.09.28
[BOJ]1722. 순열의 순서  (0) 2021.09.27
[BOJ]1351. 무한 수열  (0) 2021.09.24

문제:

뿌요뿌요의 룰은 다음과 같다.

필드에 여러 가지 색깔의 뿌요를 놓는다. 뿌요는 중력의 영향을 받아 아래에 바닥이나 다른 뿌요가 나올 때까지 아래로 떨어진다.

뿌요를 놓고 난 후, 같은 색 뿌요가 4개 이상 상하좌우로 연결되어 있으면 연결된 같은 색 뿌요들이 한꺼번에 없어진다. 이때 1연쇄가 시작된다.

뿌요들이 없어지고 나서 위에 다른 뿌요들이 있다면, 역시 중력의 영향을 받아 차례대로 아래로 떨어지게 된다.

아래로 떨어지고 나서 다시 같은 색의 뿌요들이 4개 이상 모이게 되면 또 터지게 되는데, 터진 후 뿌요들이 내려오고 다시 터짐을 반복할 때마다 1연쇄씩 늘어난다.

터질 수 있는 뿌요가 여러 그룹이 있다면 동시에 터져야 하고 여러 그룹이 터지더라도 한번의 연쇄가 추가된다.

남규는 최근 뿌요뿌요 게임에 푹 빠졌다. 이 게임은 1:1로 붙는 대전게임이라 잘 쌓는 것도 중요하지만, 상대방이 터뜨린다면 연쇄가 몇 번이 될지 바로 파악할 수 있는 능력도 필요하다. 하지만 아직 실력이 부족하여 남규는 자기 필드에만 신경 쓰기 바쁘다. 상대방의 필드가 주어졌을 때, 연쇄가 몇 번 연속으로 일어날지 계산하여 남규를 도와주자!

입력:

총 12개의 줄에 필드의 정보가 주어지며, 각 줄에는 6개의 문자가 있다.

이때 .은 빈공간이고 .이 아닌것은 각각의 색깔의 뿌요를 나타낸다.

R은 빨강, G는 초록, B는 파랑, P는 보라, Y는 노랑이다.

입력으로 주어지는 필드는 뿌요들이 전부 아래로 떨어진 뒤의 상태이다. 즉, 뿌요 아래에 빈 칸이 있는 경우는 없다.

출력:

현재 주어진 상황에서 몇연쇄가 되는지 출력한다. 하나도 터지지 않는다면 0을 출력한다.

풀이방법:

 bfs를 사용하는 문제다. 그리고 뿌요는 중력의 영향을 받아 아래에 바닥이나 다른 뿌요가 나올 때까지 아래로 떨어지는 것을 쉽게 구현하기 위해 map과 zip을 사용해서 행과 열의 위치를 바꿔서 문제를 해결했다.

 빈공간이 아닌 뿌요를 만났을 때, bfs를 수행한다. 이 때 탐색한 횟수가 4가 넘으면 방문했던 곳들을 모두 fall_이라는 곳에 다시 저장해 없어질 대상임을 표시한다. 이렇게 모든 뿌요들을 모두 탐색한 뒤에 나중에 한번에 뿌요들을 지우고 떨어지는 행동을 수행하게 한다. 이 과정이 한번이라도 발생했다면 다시 한 번 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
puyo = []
for _ in range(12):
    puyo.append(input())
    
puyo = list(map(list,zip(*puyo)))
puyo_copy = puyo.copy()
 
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(12)] for _ in range(6)]
    visited[i][j] = 1
    cnt = 1
    while queue:
        x, y = queue.popleft()
        for k in range(4):
            nx = x + dx[k]
            ny = y + dy[k]
            if 0<= nx < 6 and 0<= ny < 12 and not visited[nx][ny]:
                if puyo_copy[i][j]==puyo_copy[nx][ny]:
                    visited[nx][ny] = 1
                    queue.append((nx,ny))
                    cnt+=1
    if cnt>=4:
        for i in range(6):
            for j in range(12):
                if visited[i][j]:
                    fall_[i][j]=1
        return 1
    else:
        return 0
 
def falling():
    for i,f in enumerate(fall_):
        empty = ['.']*f.count(1)
        puyo_copy[i] = empty + [p for j,p in enumerate(puyo_copy[i]) if not f[j]]
        
time =0
while  True:
    flag=0
    fall_ = [[0 for _ in range(12)] for _ in range(6)]
    for i in range(6):
        for j in range(12):
            if puyo_copy[i][j]!='.':
                flag += bfs(i,j)
    if flag:
        time+=1
    else:
        break
    falling()
    
print(time)
cs

문제링크:

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

 

11559번: Puyo Puyo

총 12개의 줄에 필드의 정보가 주어지며, 각 줄에는 6개의 문자가 있다. 이때 .은 빈공간이고 .이 아닌것은 각각의 색깔의 뿌요를 나타낸다. R은 빨강, G는 초록, B는 파랑, P는 보라, Y는 노랑이다.

www.acmicpc.net

 

'Algorithm' 카테고리의 다른 글

[BOJ]13913. 숨바꼭질 4  (0) 2022.08.11
[BOJ]3190. 뱀  (0) 2021.08.19
[BOJ]1520. 내리막길  (0) 2021.08.17
[BOJ]1987. 알파벳  (0) 2021.08.10
[BOJ]14425. 문자열 집합  (0) 2021.06.24

문제:

아래 <그림 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

 

'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

문제:

지구 온난화로 인하여 북극의 빙산이 녹고 있다. 빙산을 그림 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

 

'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

+ Recent posts