문제:

JOI시는 남북방향이 H 킬로미터, 동서방향이 W 킬로미터인 직사각형 모양이다. JOI시는 가로와 세로의 길이가 1킬로미터인 H × W 개의 작은 구역들로 나뉘어 있다. 북쪽으로부터 i 번째, 서쪽으로부터 j 번째에 있는 구역을 (i, j) 로 표시한다.

각 구역의 하늘에는 구름이 있을 수도, 없을 수도 있다. 모든 구름은 1분이 지날 때마다 1킬로미터씩 동쪽으로 이동한다. 오늘은 날씨가 정말 좋기 때문에 JOI시의 외부에서 구름이 이동해 오는 경우는 없다.

지금 각 구역의 하늘에 구름이 있는지 없는지를 알고 있다. 기상청에서 일하고 있는 여러분은 각 구역에 대해서 지금부터 몇 분뒤 처음으로 하늘에 구름이 오는지를 예측하는 일을 맡았다.

각 구역에 대해서 지금부터 몇 분뒤 처음으로 하늘에 구름이 오는지를 구하여라.

입력:

입력은 1 + H 행으로 주어진다.

첫 번째 행에는 정수 H, W (1 ≦ H ≦ 100, 1 ≦ W ≦ 100) 가 공백을 사이에 주고 주어진다. 이것은 JOI시가 H × W 개의 작은 구역으로 나뉘어 있다는 것을 의미한다.

이어진 H 개의 행의 i번째 행 (1 ≦ i ≦ H) 에는 W문자의 문자열이 주어진다. W 개의 문자 중 j번째 문자 (1 ≦ j ≦ W) 는, 구역 (i, j) 에 지금 구름이 떠 있는지 아닌지를 나타낸다. 구름이 있는 경우에는 영어 소문자 'c' 가, 구름이 없는 경우에는 문자 '.' 가 주어진다.

출력:

출력은 H 행으로, 각 행에는 공백으로 구분된 W 개의 정수를 출력한다. 출력의 i 번째 행 j 번째 정수 (1 ≦ i ≦ H, 1 ≦ j ≦ W) 는, 지금부터 몇 분후에 처음으로 구역 (i, j) 에 구름이 뜨는지를 표시한다. 단, 처음부터 구역 (i, j) 에 구름이 떠 있었던 경우에는 0을, 몇 분이 지나도 구름이 뜨지 않을 경우에는 -1을 출력한다.

풀이방법:

주어진 조건대로 구현해야 하는 문제다. 이 문제에서는 총 3가지 행동을 수행한다.

1. 지금 하늘에 구름(c)가 있는가?

2. 구름이 몇 분뒤에 지금 하늘에 도착하는가?

3. 구름의 이동

따라서 while 계속해서 반복하고, 1에 의해서 break 조건을 만든다. 그 동안에 2와 3을 반복하며 answer 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
from collections import deque
 
def check_sky(sky):
    for i in range(H):
        for j in range(W):
            if sky[i][j]=='c':
                return 1
    return 0
 
def update_sky(sky, count):
    for i in range(H):
        for j in range(W):
            if sky[i][j]=='c':
                if answer[i][j]==-1:
                    answer[i][j] = count
 
H, W = map(int,input().split())
answer = [ [-1 for _ in range(W)] for _ in range(H)]
 
sky = []
for _ in range(H):
    sky.append(deque(input()))
    
count = 0
while True:
    if not check_sky(sky):
        break
    update_sky(sky, count)
    for i in range(H):
        sky[i].pop()
        sky[i].appendleft('.')
    count+=1
for ans in answer:
    print(*ans)
cs

문제링크:

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

 

10709번: 기상캐스터

출력은 H 행으로, 각 행에는 공백으로 구분된 W 개의 정수를 출력한다. 출력의 i 번째 행 j 번째 정수 (1 ≦ i ≦ H, 1 ≦ j ≦ W) 는, 지금부터 몇 분후에 처음으로 구역 (i, j) 에 구름이 뜨는지를 표시

www.acmicpc.net

 

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

[BOJ]2852. NBA 농구  (0) 2022.07.28
[BOJ]3474. 교수가 된 현우  (0) 2022.07.26
[BOJ]2870. 수학숙제  (0) 2022.07.19
[BOJ]11758. CCW  (0) 2022.07.14
[BOJ]4659. 비밀번호 발음하기  (0) 2022.07.12

문제:

8*8크기의 체스판에 왕이 하나 있다. 킹의 현재 위치가 주어진다. 체스판에서 말의 위치는 다음과 같이 주어진다. 알파벳 하나와 숫자 하나로 이루어져 있는데, 알파벳은 열을 상징하고, 숫자는 행을 상징한다. 열은 가장 왼쪽 열이 A이고, 가장 오른쪽 열이 H까지 이고, 행은 가장 아래가 1이고 가장 위가 8이다. 예를 들어, 왼쪽 아래 코너는 A1이고, 그 오른쪽 칸은 B1이다.

킹은 다음과 같이 움직일 수 있다.

  • R : 한 칸 오른쪽으로
  • L : 한 칸 왼쪽으로
  • B : 한 칸 아래로
  • T : 한 칸 위로
  • RT : 오른쪽 위 대각선으로
  • LT : 왼쪽 위 대각선으로
  • RB : 오른쪽 아래 대각선으로
  • LB : 왼쪽 아래 대각선으로

체스판에는 돌이 하나 있는데, 돌과 같은 곳으로 이동할 때는, 돌을 킹이 움직인 방향과 같은 방향으로 한 칸 이동시킨다. 아래 그림을 참고하자.

입력으로 킹이 어떻게 움직여야 하는지 주어진다. 입력으로 주어진 대로 움직여서 킹이나 돌이 체스판 밖으로 나갈 경우에는 그 이동은 건너 뛰고 다음 이동을 한다.

킹과 돌의 마지막 위치를 구하는 프로그램을 작성하시오.

입력:

첫째 줄에 킹의 위치, 돌의 위치, 움직이는 횟수 N이 주어진다. 둘째 줄부터 N개의 줄에는 킹이 어떻게 움직여야 하는지 주어진다. N은 50보다 작거나 같은 자연수이고, 움직이는 정보는 위에 쓰여 있는 8가지 중 하나이다.

출력:

첫째 줄에 킹의 마지막 위치, 둘째 줄에 돌의 마지막 위치를 출력한다.

풀이방법:

주어진 조건대로 구현을 하는 문제다. 이 문제에서는 크게 두 가지 조건이 있다.

 

1. 체스판 밖으로 나가는 경우에는 해당 이동을 건너 뛴다.

2. 킹이 이동하는 위치에 돌이 있다면 돌도 킹이 이동하는 방향과 같이 이동한다.

 

이 때, 1에 대한 조건은 킹에만 적용되는 것이 아니라 돌에도 적용되는 것이다. 따라서 킹을 움직였을 때, 돌이 있다면 돌을 이동시켜보고, 만약 체스판 밖으로 나간다면 킹을 다시 원래 자리로 되돌려야 한다. 해당 조건을 고려하여 command들을 구현하면 된다.

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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
def check_stone(k,s):
    if k==s:
        return 1
    else:
        return 0
king, stone, N = input().split()
x1,y1 = ord(king[0])-65int(king[1])-1
x2,y2 = ord(stone[0])-65int(stone[1])-1
size = 8
for _ in range(int(N)):
    command = input()
    if command =='R':
        if 0<= x1+1 < size:
            x1+=1
            if check_stone((x1,y1),(x2,y2)):
                if 0<= x2+1 < size:
                    x2+=1
                else:
                    x1-=1
    elif command =='L':
        if 0<= x1-1 < size:
            x1-=1
            if check_stone((x1,y1),(x2,y2)):
                if 0<= x2-1 < size:
                    x2-=1
                else:
                    x1+=1
    elif command =='B':
        if 0<= y1-1 < size:
            y1-=1
            if check_stone((x1,y1),(x2,y2)):
                if 0<= y2-1 < size:
                    y2-=1
                else:
                    y1+=1
    elif command =='T':
        if 0<= y1+1 < size:
            y1+=1
            if check_stone((x1,y1),(x2,y2)):
                if 0<= y2+1 < size:
                    y2+=1
                else:
                    y1-=1
    elif command =='RT':
        if 0<= x1+1 < size and 0<=y1+1<size:
            x1+=1
            y1+=1
            if check_stone((x1,y1),(x2,y2)):
                if 0<= x2+1 < size and 0<= y2+1 < size:
                    x2+=1
                    y2+=1
                else:
                    x1-=1
                    y1-=1
    elif command =='LT':
        if 0<= x1-1 < size and 0<=y1+1 < size:
            x1-=1
            y1+=1
            if check_stone((x1,y1),(x2,y2)):
                if 0<= x2-1 < size and 0<=y2+1<size:
                    x2-=1
                    y2+=1
                else:
                    x1+=1
                    y1-=1
    elif command =='RB':
        if 0<= x1+1 < size and 0<=y1-1<size:
            x1+=1
            y1-=1
            if check_stone((x1,y1),(x2,y2)):
                if 0<= x2+1 < size and 0<=y2-1<size:
                    x2+=1
                    y2-=1
                else:
                    x1-=1
                    y1+=1
    elif command =='LB':
        if 0<= x1-1 < size and 0<=y1-1<size:
            x1-=1
            y1-=1
            if check_stone((x1,y1),(x2,y2)):
                if 0<= x2-1 < size and 0<= y2-1<size:
                    x2-=1
                    y2-=1
                else:
                    x1+=1
                    y1+=1
print("{}{}".format(chr(x1+65), y1+1))
print("{}{}".format(chr(x2+65), y2+1))
cs

문제링크:

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

 

1063번: 킹

8*8크기의 체스판에 왕이 하나 있다. 킹의 현재 위치가 주어진다. 체스판에서 말의 위치는 다음과 같이 주어진다. 알파벳 하나와 숫자 하나로 이루어져 있는데, 알파벳은 열을 상징하고, 숫자는

www.acmicpc.net

 

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

[BOJ]1004. 어린 왕자  (0) 2022.03.22
[BOJ]2252. 줄 세우기  (0) 2022.03.17
[BOJ]2195. 문자열 복사  (0) 2022.03.10
[BOJ]2212. 센서  (0) 2022.03.08
[BOJ]17609. 회문  (0) 2022.03.03

문제:

마법사 상어는 파이어볼토네이도, 파이어스톰, 물복사버그 마법을 할 수 있다. 오늘 새로 배운 마법은 비바라기이다. 비바라기를 시전하면 하늘에 비구름을 만들 수 있다. 오늘은 비바라기를 크기가 N×N인 격자에서 연습하려고 한다. 격자의 각 칸에는 바구니가 하나 있고, 바구니는 칸 전체를 차지한다. 바구니에 저장할 수 있는 물의 양에는 제한이 없다. (r, c)는 격자의 r행 c열에 있는 바구니를 의미하고, A[r][c]는 (r, c)에 있는 바구니에 저장되어 있는 물의 양을 의미한다.

격자의 가장 왼쪽 윗 칸은 (1, 1)이고, 가장 오른쪽 아랫 칸은 (N, N)이다. 마법사 상어는 연습을 위해 1번 행과 N번 행을 연결했고, 1번 열과 N번 열도 연결했다. 즉, N번 행의 아래에는 1번 행이, 1번 행의 위에는 N번 행이 있고, 1번 열의 왼쪽에는 N번 열이, N번 열의 오른쪽에는 1번 열이 있다.

비바라기를 시전하면 (N, 1), (N, 2), (N-1, 1), (N-1, 2)에 비구름이 생긴다. 구름은 칸 전체를 차지한다. 이제 구름에 이동을 M번 명령하려고 한다. i번째 이동 명령은 방향 di과 거리 si로 이루어져 있다. 방향은 총 8개의 방향이 있으며, 8개의 정수로 표현한다. 1부터 순서대로 ←, ↖, ↑, ↗, →, ↘, ↓, ↙ 이다. 이동을 명령하면 다음이 순서대로 진행된다.

  1. 모든 구름이 di 방향으로 si칸 이동한다.
  2. 각 구름에서 비가 내려 구름이 있는 칸의 바구니에 저장된 물의 양이 1 증가한다.
  3. 구름이 모두 사라진다.
  4. 2에서 물이 증가한 칸 (r, c)에 물복사버그 마법을 시전한다. 물복사버그 마법을 사용하면, 대각선 방향으로 거리가 1인 칸에 물이 있는 바구니의 수만큼 (r, c)에 있는 바구니의 물이 양이 증가한다.
    • 이때는 이동과 다르게 경계를 넘어가는 칸은 대각선 방향으로 거리가 1인 칸이 아니다.
    • 예를 들어, (N, 2)에서 인접한 대각선 칸은 (N-1, 1), (N-1, 3)이고, (N, N)에서 인접한 대각선 칸은 (N-1, N-1)뿐이다.
  5. 바구니에 저장된 물의 양이 2 이상인 모든 칸에 구름이 생기고, 물의 양이 2 줄어든다. 이때 구름이 생기는 칸은 3에서 구름이 사라진 칸이 아니어야 한다.

M번의 이동이 모두 끝난 후 바구니에 들어있는 물의 양의 합을 구해보자.

입력:

첫째 줄에 N, M이 주어진다.

둘째 줄부터 N개의 줄에는 N개의 정수가 주어진다. r번째 행의 c번째 정수는 A[r][c]를 의미한다.

다음 M개의 줄에는 이동의 정보 di, si가 순서대로 한 줄에 하나씩 주어진다.

출력:

첫째 줄에 M번의 이동이 모두 끝난 후 바구니에 들어있는 물의 양의 합을 출력한다.

풀이방법:

 문제에서 주어진 명령어을 순서대로 진행하면 된다. 각 명령에서 다음과 같은 사항들을 주의하면 된다.

 

1. 구름이 이동할 때, 행1-행N, 열1-열N 은 연결되어 있기 때문에 % 명령어를 사용해서 구름을 이동시킨다.

2, 3. 이동한 구름의 위치를 새 배열에 담아서 +1과 이전 구름이 사라진다는 것을 구현한다.

4. 이동할 수 있는 대각선 위치에 물이 1이라도 있는지 확인하고 매번 +1한다.

5. 전체적으로 탐색을 하면서 물이 2 이상인지 확인한다.( 2,3에서 활용한 배열을 사용한다.)

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
dx = [0,-1,-1,-1,0,1,1,1]
dy = [-1,-1,0,1,1,1,0,-1]
 
N, M = map(int, input().split())
 
maps = []
for _ in range(N):
    maps.append(list(map(int, input().split())))
 
command = []
for _ in range(M):
    command.append(list(map(int, input().split())))
 
goorm = [(N-1,0),(N-1,1),(N-2,0),(N-2,1)]
 
for com in command:
    d, s = com
    move_goorm = []
    for x, y in goorm:
        nx = (x + dx[d-1]*s)%N
        ny = (y + dy[d-1]*s)%N
        move_goorm.append((nx,ny))
    for x, y in move_goorm:
        maps[x][y] += 1
    for x, y in move_goorm:
        for i in [1,3,5,7]:
            nx = x + dx[i]
            ny = y + dy[i]
            if 0<=nx<and 0<=ny<N:
                if maps[nx][ny]:
                    maps[x][y]+=1
    goorm = []
    for i in range(N):
        for j in range(N):
            if maps[i][j]>=2 and not ((i,j) in move_goorm):
                goorm.append((i,j))
                maps[i][j]-=2
 
answer = 0
for map_ in maps:
    answer += sum(map_)
print(answer)
 
 
 
cs

문제링크:

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

 

21610번: 마법사 상어와 비바라기

마법사 상어는 파이어볼, 토네이도, 파이어스톰, 물복사버그 마법을 할 수 있다. 오늘 새로 배운 마법은 비바라기이다. 비바라기를 시전하면 하늘에 비구름을 만들 수 있다. 오늘은 비바라기

www.acmicpc.net

 

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

[BOJ]2631. 줄세우기  (0) 2022.02.08
[BOJ] 9576. 책 나눠주기  (0) 2022.02.07
[BOJ]20057. 마법사 상어와 토네이도  (0) 2021.11.04
[BOJ] 15685. 드래곤 커브  (0) 2021.11.03
[BOJ]20056. 마법사 상어와 파이어볼  (0) 2021.11.02

문제:

마법사 상어가 토네이도를 배웠고, 오늘은 토네이도를 크기가 N×N인 격자로 나누어진 모래밭에서 연습하려고 한다. 위치 (r, c)는 격자의 r행 c열을 의미하고, A[r][c]는 (r, c)에 있는 모래의 양을 의미한다.

토네이도를 시전하면 격자의 가운데 칸부터 토네이도의 이동이 시작된다. 토네이도는 한 번에 한 칸 이동한다. 다음은 N = 7인 경우 토네이도의 이동이다.

토네이도가 한 칸 이동할 때마다 모래는 다음과 같이 일정한 비율로 흩날리게 된다.

토네이도가 x에서 y로 이동하면, y의 모든 모래가 비율과 α가 적혀있는 칸으로 이동한다. 비율이 적혀있는 칸으로 이동하는 모래의 양은 y에 있는 모래의 해당 비율만큼이고, 계산에서 소수점 아래는 버린다. α로 이동하는 모래의 양은 비율이 적혀있는 칸으로 이동하지 않은 남은 모래의 양과 같다. 모래가 이미 있는 칸으로 모래가 이동하면, 모래의 양은 더해진다. 위의 그림은 토네이도가 왼쪽으로 이동할 때이고, 다른 방향으로 이동하는 경우는 위의 그림을 해당 방향으로 회전하면 된다.

토네이도는 (1, 1)까지 이동한 뒤 소멸한다. 모래가 격자의 밖으로 이동할 수도 있다. 토네이도가 소멸되었을 때, 격자의 밖으로 나간 모래의 양을 구해보자.

입력:

첫째 줄에 격자의 크기 N이 주어진다. 둘째 줄부터 N개의 줄에는 격자의 각 칸에 있는 모래가 주어진다. r번째 줄에서 c번째 주어지는 정수는 A[r][c] 이다.

출력:

격자의 밖으로 나간 모래의 양을 출력한다.

풀이방법:

 이 문제의 핵심은 회오리 모양으로 토네이도가 이동하는 것을 구현, 토네이도가 이동함에 따라 모래가 흩날리는 것을 구현해야 한다.

 

우선 회오리 모양으로 이동하는 것은 다음과 같은 규칙이 있다.

 

1) 방향은 좌, 하, 우, 상 을 반복하며 진행된다.

  - 따라서 dx, dy를 +1할 때마다 방향이 좌, 하, 우, 상으로 바뀌게 설정한다.

2) 좌, 하, 우, 상으로 이동할 때 거리는 1, 1, 2, 2, 3, 3, 4, 4, .... 와 같이 매 짝수 인덱스마다 증가하게 된다.

  - 다만 맨 마지막은 N-1, N-1, N, N, N 과 같이 N이 3번 반복되며 끝난다.

 

따라서 1), 2)의 조건을 만족하며 토네이도를 이동시키고, 토네이도가 0,0에 도달하면 이동을 종료하도록 한다. (소멸)

 

 모래가 흩날리는 것은 spread라는 배열을 만들어서 해결한다. 모래가 흩날리는 것은 좌, 하, 우, 상에 따라 흩날리는 위치가 다르기 때문에 방향 인덱스에 따라 모래의 이동 인덱스를 정리해둔다. 그리고 해당 인덱스에 따라 모래가 이동할 양인 ratio를 설정하도록 한다. 이 때, a의 경우에는 ratio를 0으로 설정한 뒤 따로 설정하도록 한다. 

 global 변수 answer를 설정하고, 범위 밖으로 나가는 모래는 다 answer에 더하고, 나머지는 지도에 계속 누적시키도록 한다.

 

이 두 기능을 계속해서 반복했을 때, 최종 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
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
dx = [0,1,0,-1]
dy = [-1,0,1,0]
spread = [
    [(0,-2),(-1,-1),(1,-1),(-1,0),(1,0),(-2,0),(2,0),(-1,1),(1,1),(0,-1)],
    [(2,0),(1,-1),(1,1),(0,-1),(0,1),(0,-2),(0,2),(-1,-1),(-1,1),(1,0)],
    [(0,2),(-1,1),(1,1),(-1,0),(1,0),(-2,0),(2,0),(-1,-1),(1,-1),(0,1)],
    [(-2,0),(-1,1),(-1,-1),(0,1),(0,-1),(0,2),(0,-2),(1,1),(1,-1),(-1,0)]
]
ratio = [0.05,0.1,0.1,0.07,0.07,0.02,0.02,0.01,0.01,0]
 
def spread_sand(total, d):
    global answer
    now = spread[d]
    remain = 0
    for (x,y), rt in zip(now, ratio):
        if rt==0:
            sand = total-remain
        else:
            sand = int(total * rt)
            remain+=sand
        if 0 <= r+< N and 0 <= c+< N:
            maps[r+x][c+y] += sand
        else:
            answer += sand
    maps[r][c] = 0
 
= int(input())
 
maps = []
for _ in range(N):
    maps.append(list(map(int,input().split())))
 
r, c = N//2, N//2
idx = 0
= 0
length = 1
answer = 0
while True:
    if idx==0:
        pass
    elif idx%2==0:
        length+=1
        if length==N:
            length-=1
    if r==0 and c==0:
        break
    for _ in range(length):
        r = r + dx[d]
        c = c + dy[d]
        total = maps[r][c]
        spread_sand(total, d)
    d = (d+1)%4
    idx+=1
 
print(answer)
cs

 

문제링크:

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

 

20057번: 마법사 상어와 토네이도

마법사 상어가 토네이도를 배웠고, 오늘은 토네이도를 크기가 N×N인 격자로 나누어진 모래밭에서 연습하려고 한다. 위치 (r, c)는 격자의 r행 c열을 의미하고, A[r][c]는 (r, c)에 있는 모래의 양을

www.acmicpc.net

 

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

[BOJ] 9576. 책 나눠주기  (0) 2022.02.07
[BOJ]21610. 마법사 상어와 비바라기  (0) 2021.11.05
[BOJ] 15685. 드래곤 커브  (0) 2021.11.03
[BOJ]20056. 마법사 상어와 파이어볼  (0) 2021.11.02
[BOJ]11058. 크리보드  (0) 2021.11.01

문제:

드래곤 커브는 다음과 같은 세 가지 속성으로 이루어져 있으며, 이차원 좌표 평면 위에서 정의된다. 좌표 평면의 x축은 → 방향, y축은 ↓ 방향이다.

  1. 시작 점
  2. 시작 방향
  3. 세대

0세대 드래곤 커브는 아래 그림과 같은 길이가 1인 선분이다. 아래 그림은 (0, 0)에서 시작하고, 시작 방향은 오른쪽인 0세대 드래곤 커브이다.

1세대 드래곤 커브는 0세대 드래곤 커브를 끝 점을 기준으로 시계 방향으로 90도 회전시킨 다음 0세대 드래곤 커브의 끝 점에 붙인 것이다. 끝 점이란 시작 점에서 선분을 타고 이동했을 때, 가장 먼 거리에 있는 점을 의미한다.

2세대 드래곤 커브도 1세대를 만든 방법을 이용해서 만들 수 있다. (파란색 선분은 새로 추가된 선분을 나타낸다)

3세대 드래곤 커브도 2세대 드래곤 커브를 이용해 만들 수 있다. 아래 그림은 3세대 드래곤 커브이다.

즉, K(K > 1)세대 드래곤 커브는 K-1세대 드래곤 커브를 끝 점을 기준으로 90도 시계 방향 회전 시킨 다음, 그것을 끝 점에 붙인 것이다.

크기가 100×100인 격자 위에 드래곤 커브가 N개 있다. 이때, 크기가 1×1인 정사각형의 네 꼭짓점이 모두 드래곤 커브의 일부인 정사각형의 개수를 구하는 프로그램을 작성하시오. 격자의 좌표는 (x, y)로 나타내며, 0 ≤ x ≤ 100, 0 ≤ y ≤ 100만 유효한 좌표이다.

입력:

첫째 줄에 드래곤 커브의 개수 N(1 ≤ N ≤ 20)이 주어진다. 둘째 줄부터 N개의 줄에는 드래곤 커브의 정보가 주어진다. 드래곤 커브의 정보는 네 정수 x, y, d, g로 이루어져 있다. x와 y는 드래곤 커브의 시작 점, d는 시작 방향, g는 세대이다. (0 ≤ x, y ≤ 100, 0 ≤ d ≤ 3, 0 ≤ g ≤ 10)

입력으로 주어지는 드래곤 커브는 격자 밖으로 벗어나지 않는다. 드래곤 커브는 서로 겹칠 수 있다.

방향은 0, 1, 2, 3 중 하나이고, 다음을 의미한다.

  • 0: x좌표가 증가하는 방향 (→)
  • 1: y좌표가 감소하는 방향 (↑)
  • 2: x좌표가 감소하는 방향 (←)
  • 3: y좌표가 증가하는 방향 (↓)

출력:

첫째 줄에 크기가 1×1인 정사각형의 네 꼭짓점이 모두 드래곤 커브의 일부인 것의 개수를 출력한다.

풀이방법:

 시작점으로부터 드래곤 커브들의 방향을 구한 뒤에 모든 세대에 대한 점을 기록하는 방식으로 진행한다. 드래곤 커브를 만들 때 하나의 규칙은 N세대의 드래곤 커브를 만들기 위해 N-1세대의 끝 부터 시계 반대방향으로 90도를 회전시키면서 이어붙이면 처음부터 끝까지 한 배열에서 이어지게 만들 수 있다. 따라서 이전 세대의 끝부터 다음 세대를 진행시키도록 한다.

 모든 드래곤 커브를 그린 뒤에 100x100를 모두 탐색하며 각 꼭짓점이 모두 1인 경우만 +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
dx = [10-10]
dy = [0-101]
 
= int(input())
 
maps = [[0 for _ in range(101)] for _ in range(101)]
for _ in range(N):
    x, y, d, g = map(int, input().split())
    maps[x][y] = 1
    move = [d]
    for _ in range(g):
        temp = []
        for i in range(len(move)-1,-1,-1):
            temp.append((move[i]+1)%4)
        move.extend(temp)
 
    for m in move:
        x = x + dx[m]
        y = y + dy[m]
        maps[x][y] = 1
 
answer = 0
for i in range(100):
    for j in range(100):
        if maps[i][j]:
            if maps[i+1][j] and maps[i][j+1and maps[i+1][j+1]:
                answer += 1
print(answer)
cs

문제링크:

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

 

15685번: 드래곤 커브

첫째 줄에 드래곤 커브의 개수 N(1 ≤ N ≤ 20)이 주어진다. 둘째 줄부터 N개의 줄에는 드래곤 커브의 정보가 주어진다. 드래곤 커브의 정보는 네 정수 x, y, d, g로 이루어져 있다. x와 y는 드래곤 커

www.acmicpc.net

 

문제:

어른 상어가 마법사가 되었고, 파이어볼을 배웠다.

마법사 상어가 크기가 N×N인 격자에 파이어볼 M개를 발사했다. 가장 처음에 파이어볼은 각자 위치에서 이동을 대기하고 있다. i번 파이어볼의 위치는 (ri, ci), 질량은 mi이고, 방향은 di, 속력은 si이다. 위치 (r, c)는 r행 c열을 의미한다.

격자의 행과 열은 1번부터 N번까지 번호가 매겨져 있고, 1번 행은 N번과 연결되어 있고, 1번 열은 N번 열과 연결되어 있다.

파이어볼의 방향은 어떤 칸과 인접한 8개의 칸의 방향을 의미하며, 정수로는 다음과 같다.

7 0 1
6   2
5 4 3

마법사 상어가 모든 파이어볼에게 이동을 명령하면 다음이 일들이 일어난다.

  1. 모든 파이어볼이 자신의 방향 di로 속력 si칸 만큼 이동한다.
    • 이동하는 중에는 같은 칸에 여러 개의 파이어볼이 있을 수도 있다.
  2. 이동이 모두 끝난 뒤, 2개 이상의 파이어볼이 있는 칸에서는 다음과 같은 일이 일어난다.
    1. 같은 칸에 있는 파이어볼은 모두 하나로 합쳐진다.
    2. 파이어볼은 4개의 파이어볼로 나누어진다.
    3. 나누어진 파이어볼의 질량, 속력, 방향은 다음과 같다.
      1. 질량은 ⌊(합쳐진 파이어볼 질량의 합)/5⌋이다.
      2. 속력은 ⌊(합쳐진 파이어볼 속력의 합)/(합쳐진 파이어볼의 개수)⌋이다.
      3. 합쳐지는 파이어볼의 방향이 모두 홀수이거나 모두 짝수이면, 방향은 0, 2, 4, 6이 되고, 그렇지 않으면 1, 3, 5, 7이 된다.
    4. 질량이 0인 파이어볼은 소멸되어 없어진다.

마법사 상어가 이동을 K번 명령한 후, 남아있는 파이어볼 질량의 합을 구해보자.

입력:

첫째 줄에 N, M, K가 주어진다.

둘째 줄부터 M개의 줄에 파이어볼의 정보가 한 줄에 하나씩 주어진다. 파이어볼의 정보는 다섯 정수 ri, ci, mi, si, di로 이루어져 있다.

서로 다른 두 파이어볼의 위치가 같은 경우는 입력으로 주어지지 않는다.

출력:

마법사 상어가 이동을 K번 명령한 후, 남아있는 파이어볼 질량의 합을 출력한다.

풀이방법:

 주어진 조건대로 구현을 수행하도록 한다. 한 칸에는 여러 개의 파이어볼이 존재할 수 있기 때문에 deque로 구성되어 있는 maps을 구성하도록 한다. 주어진 입력을 모두 정리한 뒤에 K번 이동을 시작한다.

 maps를 모두 탐색하면서 하나의 파이어볼이라도 있다면 이동 명령을 수행한다. 이 때, 벽을 만나더라도 1행-N행, 1열-N열은 모두 연결되어 있기 때문에 %명령어로 이를 해결하도록 한다.

 모든 파이어볼 이동이 끝난 뒤에 다시 한번 maps를 모두 탐색하도록 한다. 이번에는 파이어볼이 2개 이상 있는 칸을 탐색하며 해당 칸에 대해 합치고 분배되는 명령을 수행하도록 한다.

 두 명령을 K번 수행한 후, maps에 남은 파이어볼의 질량을 모두 합하도록 한다.

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
62
from collections import deque
import copy
 
dx = [-1,-1,0,1,1,1,0,-1]
dy = [0,1,1,1,0,-1,-1,-1]
 
def main():
    N, M, K = map(int,input().split())
    maps = [[deque() for _ in range(N)] for _ in range(N)]
 
    for _ in range(M):
        r, c, m, s, d = map(int, input().split())
        if m!=0:
            maps[r-1][c-1].append([m,s,d])
 
    while K:
        temp = [[deque() for _ in range(N)] for _ in range(N)]
        for i in range(N):
            for j in range(N):
                if maps[i][j]:
                    while maps[i][j]:
                        m, s, d = maps[i][j].popleft()
                        nx = i + dx[d]*s
                        ny = j + dy[d]*s
                        nx = (nx + N) % N
                        ny = (ny + N) % N
                        temp[nx][ny].append([m, s, d])
 
        for i in range(N):
            for j in range(N):
                if len(temp[i][j]) > 1:
                    nm, ns, nd = 00, []
                    for m, s, d in temp[i][j]:
                        nm += m
                        ns += s
                        nd.append(d%2)
                    nm = int(nm/5)
                    if nm == 0:
                        temp[i][j] = deque()
                        continue
                    ns = int(ns/len(temp[i][j]))
                    temp[i][j] = deque()
                    if list(set(nd)) == [1or list(set(nd)) == [0]:
                        nd = [0246]
                    else:
                        nd = [1357]
                    for d in range(4):
                        temp[i][j].append([nm, ns, nd[d]])
        maps = copy.deepcopy(temp)
        K -= 1
 
    answer = 0
    for i in range(N):
        for j in range(N):
            if maps[i][j]:
                while maps[i][j]:
                    m, _, _ = maps[i][j].popleft()
                    answer += m
    print(answer)
 
if  __name__ == '__main__':
    main()
cs

문제링크:

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

 

20056번: 마법사 상어와 파이어볼

첫째 줄에 N, M, K가 주어진다. 둘째 줄부터 M개의 줄에 파이어볼의 정보가 한 줄에 하나씩 주어진다. 파이어볼의 정보는 다섯 정수 ri, ci, mi, si, di로 이루어져 있다. 서로 다른 두 파이어볼의 위치

www.acmicpc.net

 

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

[BOJ]20057. 마법사 상어와 토네이도  (0) 2021.11.04
[BOJ] 15685. 드래곤 커브  (0) 2021.11.03
[BOJ]11058. 크리보드  (0) 2021.11.01
[BOJ]14391. 종이 조각  (0) 2021.10.29
[BOJ] 2251. 물통  (0) 2021.10.28

문제:

크기가 3×3인 배열 A가 있다. 배열의 인덱스는 1부터 시작한다. 1초가 지날때마다 배열에 연산이 적용된다.

  • R 연산: 배열 A의 모든 행에 대해서 정렬을 수행한다. 행의 개수 ≥ 열의 개수인 경우에 적용된다.
  • C 연산: 배열 A의 모든 열에 대해서 정렬을 수행한다. 행의 개수 < 열의 개수인 경우에 적용된다.

한 행 또는 열에 있는 수를 정렬하려면, 각각의 수가 몇 번 나왔는지 알아야 한다. 그 다음, 수의 등장 횟수가 커지는 순으로, 그러한 것이 여러가지면 수가 커지는 순으로 정렬한다. 그 다음에는 배열 A에 정렬된 결과를 다시 넣어야 한다. 정렬된 결과를 배열에 넣을 때는, 수와 등장 횟수를 모두 넣으며, 순서는 수가 먼저이다.

예를 들어, [3, 1, 1]에는 3이 1번, 1가 2번 등장한다. 따라서, 정렬된 결과는 [3, 1, 1, 2]가 된다. 다시 이 배열에는 3이 1번, 1이 2번, 2가 1번 등장한다. 다시 정렬하면 [2, 1, 3, 1, 1, 2]가 된다.

정렬된 결과를 배열에 다시 넣으면 행 또는 열의 크기가 달라질 수 있다. R 연산이 적용된 경우에는 가장 큰 행을 기준으로 모든 행의 크기가 변하고, C 연산이 적용된 경우에는 가장 큰 열을 기준으로 모든 열의 크기가 변한다. 행 또는 열의 크기가 커진 곳에는 0이 채워진다. 수를 정렬할 때 0은 무시해야 한다. 예를 들어, [3, 2, 0, 0]을 정렬한 결과는 [3, 2]를 정렬한 결과와 같다.

행 또는 열의 크기가 100을 넘어가는 경우에는 처음 100개를 제외한 나머지는 버린다.

배열 A에 들어있는 수와 r, c, k가 주어졌을 때, A[r][c]에 들어있는 값이 k가 되기 위한 최소 시간을 구해보자.

입력:

첫째 줄에 r, c, k가 주어진다. (1 ≤ r, c, k ≤ 100)

둘째 줄부터 3개의 줄에 배열 A에 들어있는 수가 주어진다. 배열 A에 들어있는 수는 100보다 작거나 같은 자연수이다.

출력:

A[r][c]에 들어있는 값이 k가 되기 위한 연산의 최소 시간을 출력한다. 100초가 지나도 A[r][c] = k가 되지 않으면 -1을 출력한다.

풀이방법:

 연산에 따라 행과 열에 각각 행동을 취해야 하는 문제다. 일반적으로 열에다가 특정 연산을 취하는 것은 어렵기 때문에 열에 있는 내용들을 50번줄과 같이 행으로 전환해서 수행하도록 한다.

 각 행을 dict을 사용해서 갯수를 count하고 (횟수, 숫자)를 기준으로 정렬하도록 한다. 각 행을 임시 배열에 저장한 뒤에 가장 긴 행을 기준으로 나머지 부분에 0을 채워넣도록 한다. 만약 열에 대해서 수행했다면 50번줄의 코드를 다시 실행하여 열로 바꿔주도록 한다. 이를 k를 찾거나 100초가 넘을때까지 계속 반복해서 수행한다.

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
62
63
64
65
66
67
68
from collections import defaultdict
import copy
 
def make_new_A(A,max_idx):
    next_A = []
    for a in A:
        r = []
        for j in a:
            r.append(j[0])
            r.append(j[1])
        count = 0
        while 2*(max_idx-len(a))>count:
            r.append(0)
            count+=1
        next_A.append(r)
    return next_A
  
 
r,c,k = map(int,input().split())
 
= []
for _ in range(3):
    A.append(list(map(int,input().split())))
 
time = 0
while True:
    A_tmp = copy.deepcopy(A)
    if time>100:
        break
    try:
        if A_tmp[r-1][c-1]==k:
            break
    except:
        pass
    #R
    if len(A_tmp) >= len(A_tmp[0]):
        new_A = []
        max_row = 0
        for _, v in enumerate(A_tmp):
            tmp_dict = defaultdict(int)
            for i in v:
                if i:
                    tmp_dict[i]+=1
            row = sorted(tmp_dict.items(),key = lambda x : (x[1],x[0]))
            if len(row) > max_row:
                max_row = len(row)
            new_A.append(row)
        A = make_new_A(new_A,max_row)
    else:
        A_tmp = list(map(list,zip(*A_tmp)))
        new_A = []
        max_row = 0
        for _, v in enumerate(A_tmp):
            tmp_dict = defaultdict(int)
            for i in v:
                if i:
                    tmp_dict[i]+=1
            row = sorted(tmp_dict.items(),key = lambda x : (x[1],x[0]))
            if len(row) > max_row:
                max_row = len(row)
            new_A.append(row)
        A = make_new_A(new_A,max_row)
        A = list(map(list,zip(*A)))
    time+=1
if time>100:
    print(-1)
else:
    print(time)
cs

문제링크:

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

 

17140번: 이차원 배열과 연산

첫째 줄에 r, c, k가 주어진다. (1 ≤ r, c, k ≤ 100) 둘째 줄부터 3개의 줄에 배열 A에 들어있는 수가 주어진다. 배열 A에 들어있는 수는 100보다 작거나 같은 자연수이다.

www.acmicpc.net

 

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

[BOJ]1339. 단어 수학  (0) 2021.10.21
[BOJ] 15658. 연산자 끼워넣기 (2)  (0) 2021.10.20
[BOJ]2659. 십자카드 문제  (0) 2021.10.18
[BOJ] 2668. 숫자고르기  (0) 2021.10.15
[BOJ] 16918. 봄버맨  (0) 2021.10.14

문제:

봄버맨은 크기가 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

문제:

스타트링크의 사무실은 1×1크기의 정사각형으로 나누어져 있는 N×M 크기의 직사각형으로 나타낼 수 있다. 사무실에는 총 K개의 CCTV가 설치되어져 있는데, CCTV는 5가지 종류가 있다. 각 CCTV가 감시할 수 있는 방법은 다음과 같다.

1번 CCTV는 한 쪽 방향만 감시할 수 있다. 2번과 3번은 두 방향을 감시할 수 있는데, 2번은 감시하는 방향이 서로 반대방향이어야 하고, 3번은 직각 방향이어야 한다. 4번은 세 방향, 5번은 네 방향을 감시할 수 있다.

CCTV는 감시할 수 있는 방향에 있는 칸 전체를 감시할 수 있다. 사무실에는 벽이 있는데, CCTV는 벽을 통과할 수 없다. CCTV가 감시할 수 없는 영역은 사각지대라고 한다.

CCTV는 회전시킬 수 있는데, 회전은 항상 90도 방향으로 해야 하며, 감시하려고 하는 방향이 가로 또는 세로 방향이어야 한다.

지도에서 0은 빈 칸, 6은 벽, 1~5는 CCTV의 번호이다. 위의 예시에서 1번의 방향에 따라 감시할 수 있는 영역을 '#'로 나타내면 아래와 같다.

CCTV는 벽을 통과할 수 없기 때문에, 1번이 → 방향을 감시하고 있을 때는 6의 오른쪽에 있는 칸을 감시할 수 없다.

위의 예시에서 감시할 수 있는 방향을 알아보면 아래와 같다.

CCTV는 CCTV를 통과할 수 있다. 아래 예시를 보자.

위와 같은 경우에 2의 방향이 ↕ 3의 방향이 ←와 ↓인 경우 감시받는 영역은 다음과 같다.

사무실의 크기와 상태, 그리고 CCTV의 정보가 주어졌을 때, CCTV의 방향을 적절히 정해서, 사각 지대의 최소 크기를 구하는 프로그램을 작성하시오.

입력:

첫째 줄에 사무실의 세로 크기 N과 가로 크기 M이 주어진다. (1 ≤ N, M ≤ 8)

둘째 줄부터 N개의 줄에는 사무실 각 칸의 정보가 주어진다. 0은 빈 칸, 6은 벽, 1~5는 CCTV를 나타내고, 문제에서 설명한 CCTV의 종류이다. 

CCTV의 최대 개수는 8개를 넘지 않는다.

출력:

첫째 줄에 사각 지대의 최소 크기를 출력한다.

풀이방법:

 CCTV 번호에 따라 감시할 수 있는 방향이 다르고, 같은 번호라도 회전이 가능하기 때문에 같은 번호도 서로 다른 방향을 가리킬 수 있다. 각 번호에 따라 나올 수 있는 경우의 수는 동,서,남,북 4가지 경우밖에 없다. 따라서 CCTV 번호에 따라 기준이 되는 축을 기준으로 동,서,남,북으로 각각 배정을 해보며 사각지대가 최소가 되는 경우를 찾도록 한다. 즉, 백트래킹을 사용해 모든 경우에 대해 계산한다고 생각하면 된다.

 cctv를 설정하기에 앞서서 지도 상의 cctv의 개수와 좌표를 먼저 배열에 담아둔다. 이 배열을 기준으로 모든 cctv가 배치되었는지 확인하기 때문이다. 이 작업을 모두 마친 뒤 cctv를 하나씩 배치하도록 한다. 방향에 따라, 번호에 따라 cctv를 설정하며, 매 cctv 설정마다 visited를 최신화하여 사각지대를 계산할 수 있도록 한다. 또한 같은 번호의 cctv를 추후 회전하는 것을 고려하기 위해 rollback이라는 배열에 cctv가 탐색할 수 있는 좌표들을 담아 다시 되돌릴 수 있도록 한다.

 cctv를 모두 설정할 때마다 사각지대의 수를 구하며, 그 중 가장 최소인 값을 출력하도록 한다.

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
62
63
64
65
66
67
68
69
70
71
72
73
74
dx = [-1010]
dy = [010-1]
 
def watch(idx):
    global answer
    if idx==cctv_count:
        tmp = 0
        for i in range(N):
            for j in range(M):
                if not visited[i][j] and not office[i][j]:
                    tmp+=1
        return tmp
    x,y = cctvs[idx]
    for i in range(4):
        del_dir = []
        if office[x][y]==1:
            del_dir.append(i)
        elif office[x][y]==2:
            del_dir.append(i)
            del_dir.append((i+2)%4)
        elif office[x][y]==3:
            del_dir.append(i)
            del_dir.append((i+1)%4)
        elif office[x][y]==4:
            del_dir.append(i)
            del_dir.append((i+1)%4)
            del_dir.append((i+2)%4)
        elif office[x][y]==5:
            del_dir.append(i)
            del_dir.append((i+1)%4)
            del_dir.append((i+2)%4)
            del_dir.append((i+3)%4)
            
        rollback = []
        for dd in del_dir:
            nx,ny = x,y
            while True:
                nx, ny = nx + dx[dd], ny+dy[dd]
                if 0<=nx<and 0<=ny<M:
                    if not visited[nx][ny]:
                        if office[nx][ny]!=6:
                            visited[nx][ny] = 1
                            rollback.append((nx,ny))
                        else:
                            break
                else:
                    break
 
        answer = min(answer,watch(idx+1))
        for rb in rollback:
            bx,by = rb
            if not office[bx][by]:
                visited[bx][by] = 0
        if office[x][y]==5:
            return answer
    return answer
 
N, M = map(int,input().split())
office = []
for _ in range(N):
    office.append(list(map(int,input().split())))
 
visited = [[0 for _ in range(M)] for _ in range(N)]
cctvs = []
cctv_count = 0
answer = N*
for i in range(N):
    for j in range(M):
        if office[i][j] and office[i][j] !=6:
            cctvs.append((i,j))
            visited[i][j] = 1
            cctv_count+=1
answer = watch(0)
print(answer)
cs

문제링크:

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

 

15683번: 감시

스타트링크의 사무실은 1×1크기의 정사각형으로 나누어져 있는 N×M 크기의 직사각형으로 나타낼 수 있다. 사무실에는 총 K개의 CCTV가 설치되어져 있는데, CCTV는 5가지 종류가 있다. 각 CCTV가 감

www.acmicpc.net

 

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

[BOJ] 16918. 봄버맨  (0) 2021.10.14
[BOJ] 16236. 아기 상어  (0) 2021.10.13
[BOJ] 14500. 테트로미노  (0) 2021.10.08
[BOJ]2458. 키 순서  (0) 2021.10.07
[BOJ] 21608. 상어 초등학교  (0) 2021.10.06

문제:

2차원 세계에 블록이 쌓여있다. 비가 오면 블록 사이에 빗물이 고인다.

비는 충분히 많이 온다. 고이는 빗물의 총량은 얼마일까?

입력:

첫 번째 줄에는 2차원 세계의 세로 길이 H과 2차원 세계의 가로 길이 W가 주어진다. (1 ≤ H, W ≤ 500)

두 번째 줄에는 블록이 쌓인 높이를 의미하는 0이상 H이하의 정수가 2차원 세계의 맨 왼쪽 위치부터 차례대로 W개 주어진다.

따라서 블록 내부의 빈 공간이 생길 수 없다. 또 2차원 세계의 바닥은 항상 막혀있다고 가정하여도 좋다.

출력:

2차원 세계에서는 한 칸의 용량은 1이다. 고이는 빗물의 총량을 출력하여라.

빗물이 전혀 고이지 않을 경우 0을 출력하여라.

풀이방법:

 양 끝점을 제외한 칸에서부터 왼쪽과 오른쪽을 각각 탐색해서 가장 낮은 위치를 찾아내고, 왼쪽의 가장 낮은 위치와 오른쪽의 가장 낮은 위치 더 낮은 값이 해당 칸에 빗물이 고인 수치다. 이 과정을 모든 칸에 진행하면서 값을 누적시키면 최종 답을 구할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
H, W = map(int,input().split())
block = list(map(int,input().split()))
 
answer = 0
for cur in range(1, W-1):
    left_block = block[cur]
    for i in range(cur-1,-1,-1):
        if left_block < block[i]:
            left_block = block[i]
    right_block = block[cur]
    for j in range(cur+1,W):
        if right_block < block[j]:
            right_block = block[j]
    min_block = min(left_block, right_block)
    answer += min_block-block[cur]
print(answer)
cs

문제링크:

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

 

14719번: 빗물

첫 번째 줄에는 2차원 세계의 세로 길이 H과 2차원 세계의 가로 길이 W가 주어진다. (1 ≤ H, W ≤ 500) 두 번째 줄에는 블록이 쌓인 높이를 의미하는 0이상 H이하의 정수가 2차원 세계의 맨 왼쪽 위치

www.acmicpc.net

 

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

[BOJ]1057. 토너먼트  (0) 2021.09.16
[BOJ] 14890. 경사로  (0) 2021.09.15
[BOJ]2470. 두 용액  (0) 2021.09.13
[BOJ]1655. 가운데를 말해요  (0) 2021.09.10
[BOJ]2110. 공유기 설치  (0) 2021.09.09

+ Recent posts