문제:

오목은 바둑판에 검은 바둑알과 흰 바둑알을 교대로 놓아서 겨루는 게임이다. 바둑판에는 19개의 가로줄과 19개의 세로줄이 그려져 있는데 가로줄은 위에서부터 아래로 1번, 2번, ... ,19번의 번호가 붙고 세로줄은 왼쪽에서부터 오른쪽으로 1번, 2번, ... 19번의 번호가 붙는다.

위의 그림에서와 같이 같은 색의 바둑알이 연속적으로 다섯 알을 놓이면 그 색이 이기게 된다. 여기서 연속적이란 가로, 세로 또는 대각선 방향 모두를 뜻한다. 즉, 위의 그림은 검은색이 이긴 경우이다. 하지만 여섯 알 이상이 연속적으로 놓인 경우에는 이긴 것이 아니다.

입력으로 바둑판의 어떤 상태가 주어졌을 때, 검은색이 이겼는지, 흰색이 이겼는지 또는 아직 승부가 결정되지 않았는지를 판단하는 프로그램을 작성하시오. 단, 검은색과 흰색이 동시에 이기거나 검은색 또는 흰색이 두 군데 이상에서 동시에 이기는 경우는 입력으로 들어오지 않는다.

입력:

19줄에 각 줄마다 19개의 숫자로 표현되는데, 검은 바둑알은 1, 흰 바둑알은 2, 알이 놓이지 않는 자리는 0으로 표시되며, 숫자는 한 칸씩 띄어서 표시된다.

출력:

첫줄에 검은색이 이겼을 경우에는 1을, 흰색이 이겼을 경우에는 2를, 아직 승부가 결정되지 않았을 경우에는 0을 출력한다. 검은색 또는 흰색이 이겼을 경우에는 둘째 줄에 연속된 다섯 개의 바둑알 중에서 가장 왼쪽에 있는 바둑알(연속된 다섯 개의 바둑알이 세로로 놓인 경우, 그 중 가장 위에 있는 것)의 가로줄 번호와, 세로줄 번호를 순서대로 출력한다.

풀이방법:

 이 문제는 오목인지는 판정한 뒤에 육목에 해당하는지에 판단 여부가 중요한 문제다. 우선 19x19의 모든 점에서 흰돌이나 검은돌이 있다면 오목인지 판정을 시작한다. 오목을 판정하는 방법은 해당 점으로 부터 8 방향으로 움직이며 돌이 연속되는지 판단하도록 한다. 기준점으로부터 연속하여 4개가 더 있다면 우선 오목이라고 판정한다. 그리고 한 번 더 해당 방향으로 이동하고, 처음 기준점에서 움직였던 반대 방향(180도 반대)으로 한 칸씩 움직여서 육목의 여부 판정을 더 수행한다. 정확한 오목이라면 값을 반환하고 저장하도록 한다.

 동시에 이기는 경우는 없기 때문에 값을 가지고 있는 리스트의 인덱스가 정답에 해당하며, 조건에 맞게(가장 왼쪽에 있는 바둑알) 출력하도록 한다. 만약 둘 다 비어 있다면 아직 승부가 결정되지 않은 경우이므로 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
47
48
49
50
51
dx = [0-1-1-10111]
dy = [110-1-1-101]
def check_win(x,y):
    key = board[x][y]
    for i in range(8):
        find = False
        tx,ty = x,y
        for j in range(4):
            nx = tx + dx[i]
            ny = ty + dy[i]
            if 0<= nx < 19 and 0<= ny <19:
                if key==board[nx][ny]:
                    tx, ty = nx, ny
                    find = True
                    continue
                else:
                    find = False
                    break
            else:
                find=False
                break
        if find:
            nx, ny = tx+dx[i], ty+dy[i]
            if 0<=nx<19 and 0<=ny<19:
                if key==board[nx][ny]:
                    continue
            ti = (i+4)%8
            nx, ny = x+dx[ti], y+dy[ti]
            if 0<=nx<19 and 0<=ny<19:
                if key==board[nx][ny]:
                    continue
            return 1
    return 0
 
board = []
for _ in range(19):
    board.append(list(map(int,input().split())))
 
answer = [[],[]]
for i in range(19):
    for j in range(19):
        if board[i][j]:
            if check_win(i,j):
                answer[board[i][j]-1].append((i+1,j+1))
for i in range(2):
    if answer[i]:
        answer_list = sorted(answer[i], key=lambda x: x[1])
        print(i+1)
        print(*answer_list[0])
if not len(answer[0]) and not len(answer[1]):
    print(0)
cs

문제링크:

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

 

2615번: 오목

오목은 바둑판에 검은 바둑알과 흰 바둑알을 교대로 놓아서 겨루는 게임이다. 바둑판에는 19개의 가로줄과 19개의 세로줄이 그려져 있는데 가로줄은 위에서부터 아래로 1번, 2번, ... ,19번의 번호

www.acmicpc.net

 

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

[BOJ]2635. 수 이어가기  (0) 2022.04.19
[BOJ]2596. 비밀편지  (0) 2022.04.14
[BOJ]2628. 종이자르기  (0) 2022.04.07
[BOJ]9205. 맥주 마시면서 걸어가기  (0) 2022.04.05
[BOJ]1439. 뒤집기  (0) 2022.03.31

문제:

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과 P를 가지고  다음 과정을 거쳐서 나오는 숫자들을 차례대로 출력해보자. 처음 출력하는 숫자는 N이고, 두 번째 이후 출력하는  숫자들은 N을 곱하고 P로 나눈 나머지를 구하는 과정을 반복하여 구한다. 즉, 먼저 N에 N을 곱하고, 이 수를 P로 나눈 나머지를 두 번째에 출력한다. 다음에는 이 나머지에 N을 곱하고 P로 나눈 나머지를 출력한다. 다음에는 이 나머지에 N을 곱한 후 P로 나눈 나머지를 출력한다. 이 과정을 계속 반복해보면 출력되는 숫자들에는 반복되는 부분이 있다.

예를 들어서, N=67, P=31인 경우를 생각해보자. 처음 출력되는 숫자는 67이고, 두 번째로 출력되는 숫자는 67×67 = 4489를 31로 나눈 나머지 25이다. 다음에는 25×67 = 1675를 31로 나눈 나머지 1, 다음에는 1×67 = 67을 31로 나눈 나머지 5가 차례대로 출력된다. 다음에는 5×67 = 335를 31로 나눈 나머지 25가 출력되는데, 이 수는 이미 이전에 출력된 수이다. 이 과정을 그림으로 보이면 다음과 같다.

즉 이 과정을 반복하면, 처음 67을 제외하면 3개의 숫자 25, 1, 5가 계속 무한히 반복되게 된다.   또 다른 예로, N=9, P=3을 가지고 시작하면, 9×9 = 81이고 3으로 나눈 나머지는 0이며, 0×3 = 0이고 3으로 나눈 나머지도 0이기 때문에 처음 9를 제외하면 0이 무한히 반복되게 된다. 

N과 P를 입력받아 위와 같이 정의된 연산을 수행하였을 때,  반복되는 부분에 포함된 서로 다른 숫자의 개수를 구하는 프로그램을 작성하시오.

입력:

첫째 줄에 처음 시작하는 N과 P가 공백을 사이에 두고 주어진다. 단, 1 ≤ N ≤ 1,000, 2 ≤ P ≤ 97이다.  

출력:

첫째 줄에 반복되는 부분에 포함된 서로 다른 숫자의 개수를 출력한다.

풀이방법:

 while 반복문을 사용하여, 주어진 조건에 따라 계속해서 연산을 진행하다가 memory에 같은 같이 존재하면 반복문을 종료하는 방식으로 문제를 해결한다. 이 때, 싸이클이 반드시 처음 시작한 숫자로부터 시작되는 것이 아니기 때문에 종료된 숫자가 있는 인덱스를 찾아서 전체 memory에서 빼줌으로써 싸이클의 길이를 계산한다.

1
2
3
4
5
6
7
8
9
10
n, p = map(int,input().split())
memory = []
next_ = n
while True:
    next_ = (next_*n) % p
    if next_ in memory:
        break
    else:
        memory.append(next_)
print(len(memory)-memory.index(next_))
cs

문제링크:

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

 

2526번: 싸이클

두 자연수 N과 P를 가지고  다음 과정을 거쳐서 나오는 숫자들을 차례대로 출력해보자. 처음 출력하는 숫자는 N이고, 두 번째 이후 출력하는  숫자들은 N을 곱하고 P로 나눈 나머지를 구하는 과

www.acmicpc.net

 

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

[BOJ]1916. 최소비용 구하기  (0) 2022.02.18
[BOJ]11689. GCD(n,k) = 1  (0) 2022.02.16
[BOJ]2641. 다각형그리기  (0) 2022.02.11
[BOJ]2660. 회장뽑기  (0) 2022.02.10
[BOJ]10827. a^b  (0) 2022.02.09

문제:

모눈종이에 다각형을 그리려고 한다. 그리는 방법은 모양수열로 표시된다. 모양수열은 1과 4사이의 숫자가 연속되어 나열된 것으로 1은 오른쪽으로, 2는 위쪽으로, 3은 왼쪽으로, 4는 아래쪽으로 한 칸씩 그리는 것을 말한다.

예를 들어 아래 그림의 다각형 (2)는 점 A에서 시작하여 화살표 방향으로 모양수열 1411433322를 따라서 그린 것이다. 다각형 (3)은 점 B에서 시작하여 화살표 방향으로 모양수열 3221411433을 따라서 그린 것이다. 또한 다각형(4)는 점 C에서 시작하여 화살표 방향으로 모양수열 4411123323을 따라서 그린 것이다. 다각형 (2), (3), (4)는 다각형 (1)과 같으므로 모양수열들 1411433322, 3221411433, 4411123323은 모두 같은 다각형을 그릴 수 있다. 단, 다각형이 회전된 것이나 뒤집어진 것은 같은 다각형이 아니다. 그러므로 아래 그림의 다각형 (5)와 (6)은 다각형 (1)과 다르다.

한 개의 표본 모양수열과 여러 모양수열들이 주어졌을 때 표본 모양수열과 같은 다각형을 그릴 수 있는 모양수열들을 모두 찾는 프로그램을 작성하시오.

입력:

첫째 줄에는 표본 모양수열의 길이(숫자의 개수)가 주어지고, 둘째 줄에는 표본 모양수열이 주어진다. 셋째 줄에는 모양수열의 개수가 주어지고 넷째 줄부터는 각 줄에 표본 모양수열과 같은 길이의 모양수열이 하나씩 주어진다. 단, 모양수열들의 개수는 최대 100 개이고 모양수열의 길이는 최대 50 이다. 모양수열의 각 숫자 사이에는 빈칸이 하나 있다.

출력:

첫째 줄에는 입력된 표본 모양수열과 같은 다각형을 그리는 모양수열들의 개수를 출력한다. 둘째 줄부터는 각 줄에 표본 모양수열과 같은 다각형을 그릴 수 있는 모양수열을 출력한다. 출력되는 모양수열의 숫자들은 한 칸 띄고 출력한다.

풀이방법:

발생할 수 있는 경우의 수는 크게 두 가지다. 첫번째는 시계방향으로 진행하는 방법, 혹은 반시계방향으로 진행하는 방법이다.

따라서 주어진 표본 모양수열이 있으면 그 모양을 반대로 진행시킨 것을 생성하고, 각각 deque의 rotate 기능을 사용하여 회전시켜서 모든 경우의 수를 만든다. 그리고 주어진 입력이 이 경우의 수에 존재한다면 출력하고, 그렇지 않다면 넘어가도록 한다.

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
from collections import deque
 
dx = [1,0,-1,0]
dy = [0,1,0,-1]
= int(input())
standard = list(map(int,input().split()))
standard = deque(standard)
reversed_s = []
for s in standard:
    if s==1:
        r = 3
    elif s==2:
        r = 4
    elif s==3:
        r = 1
    elif s==4:
        r = 2
    reversed_s.append(r)
 
reversed_s.reverse()
reversed_s = deque(reversed_s)
candidate = []
while n:
    standard.rotate(1)
    reversed_s.rotate(1)
    n-=1
    candidate.append(list(standard))
    candidate.append(list(reversed_s))
 
answer = []
= int(input())
for _ in range(m):
    s = list(map(int,input().split()))
    if s in candidate:
        answer.append(s)
print(len(answer))
for a in answer:
    print(*a)
cs

문제링크:

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

 

2641번: 다각형그리기

모눈종이에 다각형을 그리려고 한다. 그리는 방법은 모양수열로 표시된다. 모양수열은 1과 4사이의 숫자가 연속되어 나열된 것으로 1은 오른쪽으로, 2는 위쪽으로, 3은 왼쪽으로, 4는 아래쪽으로

www.acmicpc.net

 

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

[BOJ]11689. GCD(n,k) = 1  (0) 2022.02.16
[BOJ]2526. 싸이클  (0) 2022.02.14
[BOJ]2660. 회장뽑기  (0) 2022.02.10
[BOJ]10827. a^b  (0) 2022.02.09
[BOJ]2631. 줄세우기  (0) 2022.02.08

문제:

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

문제:

민식이는 수학학원에서 단어 수학 문제를 푸는 숙제를 받았다.

단어 수학 문제는 N개의 단어로 이루어져 있으며, 각 단어는 알파벳 대문자로만 이루어져 있다. 이때, 각 알파벳 대문자를 0부터 9까지의 숫자 중 하나로 바꿔서 N개의 수를 합하는 문제이다. 같은 알파벳은 같은 숫자로 바꿔야 하며, 두 개 이상의 알파벳이 같은 숫자로 바뀌어지면 안 된다.

예를 들어, GCF + ACDEB를 계산한다고 할 때, A = 9, B = 4, C = 8, D = 6, E = 5, F = 3, G = 7로 결정한다면, 두 수의 합은 99437이 되어서 최대가 될 것이다.

N개의 단어가 주어졌을 때, 그 수의 합을 최대로 만드는 프로그램을 작성하시오.

입력:

첫째 줄에 단어의 개수 N(1 ≤ N ≤ 10)이 주어진다. 둘째 줄부터 N개의 줄에 단어가 한 줄에 하나씩 주어진다. 단어는 알파벳 대문자로만 이루어져있다. 모든 단어에 포함되어 있는 알파벳은 최대 10개이고, 수의 최대 길이는 8이다. 서로 다른 문자는 서로 다른 숫자를 나타낸다.

출력:

첫째 줄에 주어진 단어의 합의 최댓값을 출력한다.

풀이방법:

 모든 케이스에 대해 수행하기에는 경우의 수가 너무 많기 때문에 그리디하게 이 문제를 해결하도록 한다. 각 알파벳에 대해 가중치를 구한 뒤에 가중치가 높은 순서대로 9부터 숫자를 할당하면 된다.

 가중치는 알파벳이 있는 위치, 갯수에 따라 다르게 설정한다. ABC와 같이 있을 때, 이를 숫자로 보면 A00, B0, C와 같다. 즉 자릿수가 클수록 더 높은 가중치를 가지게 된다. 따라서 word를 순회하면서 가중치를 순회하도록 한다. 이를 dict 형태로 저장하는데, 불필요한 키들을 줄이기 위해 defaultdict을 사용하여 깔끔하게 정리하도록 한다.

 최종적으로는 가중치에 따라 값을 부여하고 합을 누적시키도록 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from collections import defaultdict
 
def word2number(word):
    for i in range(len(word)):
        alpha[word[i]] += pow(10,len(word)-i-1)
        
= int(input())
alpha = defaultdict(int)
for _ in range(N):
    word = input()
    word2number(word)
 
imp_list = sorted(alpha.items(),key = lambda x: -x[1])
answer = 0
number = 9
for imp in imp_list:
    answer+=imp[1]*number
    number-=1
print(answer)
cs

문제링크:

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

 

1339번: 단어 수학

첫째 줄에 단어의 개수 N(1 ≤ N ≤ 10)이 주어진다. 둘째 줄부터 N개의 줄에 단어가 한 줄에 하나씩 주어진다. 단어는 알파벳 대문자로만 이루어져있다. 모든 단어에 포함되어 있는 알파벳은 최대

www.acmicpc.net

 

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

[BOJ] 15988. 1, 2, 3 더하기  (0) 2021.10.25
[BOJ] 13023. ABCDE  (0) 2021.10.22
[BOJ] 15658. 연산자 끼워넣기 (2)  (0) 2021.10.20
[BOJ] 17140. 이차원 배열과 연산  (0) 2021.10.19
[BOJ]2659. 십자카드 문제  (0) 2021.10.18

문제:

N개의 수로 이루어진 수열 A1, A2, ..., AN이 주어진다. 또, 수와 수 사이에 끼워넣을 수 있는 연산자가 주어진다. 연산자는 덧셈(+), 뺄셈(-), 곱셈(×), 나눗셈(÷)으로만 이루어져 있다. 연산자의 개수는 N-1보다 많을 수도 있다. 모든 수의 사이에는 연산자를 한 개 끼워넣어야 하며, 주어진 연산자를 모두 사용하지 않고 모든 수의 사이에 연산자를 끼워넣을 수도 있다.

우리는 수와 수 사이에 연산자를 하나씩 넣어서, 수식을 하나 만들 수 있다. 이때, 주어진 수의 순서를 바꾸면 안 된다.

예를 들어, 6개의 수로 이루어진 수열이 1, 2, 3, 4, 5, 6이고, 주어진 연산자가 덧셈(+) 3개, 뺄셈(-) 2개, 곱셈(×) 1개, 나눗셈(÷) 1개인 경우에는 총 250가지의 식을 만들 수 있다. 예를 들어, 아래와 같은 식을 만들 수 있다.

  • 1+2+3-4×5÷6
  • 1÷2+3+4-5×6
  • 1+2÷3×4-5+6
  • 1÷2×3-4+5+6
  • 1+2+3+4-5-6
  • 1+2+3-4-5×6

식의 계산은 연산자 우선 순위를 무시하고 앞에서부터 진행해야 한다. 또, 나눗셈은 정수 나눗셈으로 몫만 취한다. 음수를 양수로 나눌 때는 C++14의 기준을 따른다. 즉, 양수로 바꾼 뒤 몫을 취하고, 그 몫을 음수로 바꾼 것과 같다. 이에 따라서, 위의 식 4개의 결과를 계산해보면 아래와 같다.

  • 1+2+3-4×5÷6 = 1
  • 1÷2+3+4-5×6 = 12
  • 1+2÷3×4-5+6 = 5
  • 1÷2×3-4+5+6 = 7
  • 1+2+3+4-5-6 = -1
  • 1+2+3-4-5×6 = -18

N개의 수와 연산자가 주어졌을 때, 만들 수 있는 식의 결과가 최대인 것과 최소인 것을 구하는 프로그램을 작성하시오.

입력:

첫째 줄에 수의 개수 N(2 ≤ N ≤ 11)가 주어진다. 둘째 줄에는 A1, A2, ..., AN이 주어진다. (1 ≤ Ai ≤ 100) 셋째 줄에는 합이 N-1보다 크거나 같고, 4N보다 작거나 같은 4개의 정수가 주어지는데, 차례대로 덧셈(+)의 개수, 뺄셈(-)의 개수, 곱셈(×)의 개수, 나눗셈(÷)의 개수이다. 

출력:

첫째 줄에 만들 수 있는 식의 결과의 최댓값을, 둘째 줄에는 최솟값을 출력한다. 연산자를 어떻게 끼워넣어도 항상 -10억보다 크거나 같고, 10억보다 작거나 같은 결과가 나오는 입력만 주어진다. 또한, 앞에서부터 계산했을 때, 중간에 계산되는 식의 결과도 항상 -10억보다 크거나 같고, 10억보다 작거나 같다.

풀이방법:

 처음에는 이 문제를 permutation을 사용해서 풀려고 했으나 시간초과나 메모리초과가 발생하게 되었다. 따라서 조금 더 효율적인 방법을 찾고자 고안한 방법은 백트래킹 방법이다.

 permutation은 매 candidate마다 값을 계산해야 한다. 하지만 1,1,3이라는 숫자가 있을 때, 1+1을 한번만 구한 뒤에 3에다가 추가적인 연산을 하는 것이 더 효율적이다. 따라서 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
25
26
27
28
29
30
31
32
33
34
35
36
= int(input())
numbers = list(map(int,input().split()))
counts = list(map(int,input().split()))
max_answer = -float('inf')
min_answer = float('inf')
 
def dfs(num_idx, value):
    global max_answer, min_answer
    if num_idx == N:
        max_answer = max(max_answer, value)
        min_answer = min(min_answer, value)
        return
    if counts[0> 0:
        counts[0-= 1
        dfs(num_idx+1, value+numbers[num_idx])
        counts[0+= 1
    if counts[1> 0:
        counts[1-= 1
        dfs(num_idx+1, value-numbers[num_idx])
        counts[1+= 1
    if counts[2> 0:
        counts[2-= 1
        dfs(num_idx+1, value*numbers[num_idx])
        counts[2+= 1
    if counts[3> 0:
        counts[3-= 1
        if value < 0:
            tmp = -(abs(value)//numbers[num_idx])
        else:
            tmp = value//numbers[num_idx]
        dfs(num_idx+1, tmp)
        counts[3+= 1
 
dfs(1,numbers[0])
print(max_answer)
print(min_answer)
cs

문제링크:

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

 

15658번: 연산자 끼워넣기 (2)

첫째 줄에 수의 개수 N(2 ≤ N ≤ 11)가 주어진다. 둘째 줄에는 A1, A2, ..., AN이 주어진다. (1 ≤ Ai ≤ 100) 셋째 줄에는 합이 N-1보다 크거나 같고, 4N보다 작거나 같은 4개의 정수가 주어지는데, 차례대

www.acmicpc.net

 

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

[BOJ] 13023. ABCDE  (0) 2021.10.22
[BOJ]1339. 단어 수학  (0) 2021.10.21
[BOJ] 17140. 이차원 배열과 연산  (0) 2021.10.19
[BOJ]2659. 십자카드 문제  (0) 2021.10.18
[BOJ] 2668. 숫자고르기  (0) 2021.10.15

+ Recent posts