문제:

2017년 4월 5일 식목일을 맞이한 진아는 나무를 심는 대신 하이테크관 앞 화단에 꽃을 심어 등교할 때 마다 꽃길을 걷고 싶었다.

진아가 가진 꽃의 씨앗은 꽃을 심고나면 정확히 1년후에 꽃이 피므로 진아는 다음해 식목일 부터 꽃길을 걸을 수 있다.

하지만 진아에게는 꽃의 씨앗이 세개밖에 없었으므로 세 개의 꽃이 하나도 죽지 않고 1년후에 꽃잎이 만개하길 원한다.

꽃밭은 N*N의 격자 모양이고 진아는 씨앗을 (1,1)~(N,N)의 지점 중 한곳에 심을 수 있다. 꽃의 씨앗은 그림 (a)처럼 심어지며 1년 후 꽃이 피면 그림 (b)모양이 된다.

꽃을 심을 때는 주의할 점이있다. 어떤 씨앗이 꽃이 핀 뒤 다른 꽃잎(혹은 꽃술)과 닿게 될 경우 두 꽃 모두 죽어버린다. 또 화단 밖으로 꽃잎이 나가게 된다면 그 꽃은 죽어버리고 만다.

그림(c)는 세 꽃이 정상적으로 핀 모양이고 그림(d)는 두 꽃이 죽어버린 모양이다.

하이테크 앞 화단의 대여 가격은 격자의 한 점마다 다르기 때문에 진아는 서로 다른 세 씨앗을 모두 꽃이 피게하면서 가장 싼 가격에 화단을 대여하고 싶다.

단 화단을 대여할 때는 꽃잎이 핀 모양을 기준으로 대여를 해야하므로 꽃 하나당 5평의 땅을 대여해야만 한다.

돈이 많지 않은 진아를 위하여 진아가 꽃을 심기 위해 필요한 최소비용을 구해주자!

입력:

입력의 첫째 줄에 화단의 한 변의 길이 N(6≤N≤10)이 들어온다.

이후 N개의 줄에 N개씩 화단의 지점당 가격(0≤G≤200)이 주어진다.

출력:

꽃을 심기 위한 최소 비용을 출력한다.

풀이방법:

화단의 한 변의 길이가 가장 큰 경우는 10이며, 꽃은 3개를 심을 수 있다. 이 때 양 끝 라인들은 꽃을 심을 경우 화단 밖으로 꽃잎이 나가게 되므로, 심지 못하는 구간이다. 따라서 8x8의 점에서 3개를 선택하는 것과 같다. 많지 않은 케이스를 가지고 있으므로, 모든 경우의 수를 구하고, 가능한지 여부를 파악한다. 그래서 가능한 경우에 비용만을 체크하여 최소 비용을 찾는다.

 따라서 combination을 사용하여 모든 케이스를 확인하고, 각 케이스에 대해 한 번의 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
from itertools import combinations
 
dx = [-1010]
dy = [010-1]
 
def check(flowers):
    global answer
    flower_range = []
    cost = 0
    for x, y in flowers:
        flower_range.append((x,y))
        cost += maps[x][y]
        for i in range(4):
            nx = x +dx[i]
            ny = y +dy[i]
            if (nx,ny) not in flower_range:
                flower_range.append((nx, ny))
                cost += maps[nx][ny]
            else:
                return
    answer = min(answer, cost)
 
= int(input())
maps = []
for _ in range(N):
    maps.append(list(map(int,input().split())))
 
candidates = [(x, y) for x in range(1, N-1for y in range(1, N-1)]
answer = float('inf'
for can in combinations(candidates, 3):
    check(can)
print(answer)
cs

문제링크:

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

 

14620번: 꽃길

2017년 4월 5일 식목일을 맞이한 진아는 나무를 심는 대신 하이테크관 앞 화단에 꽃을 심어 등교할 때 마다 꽃길을 걷고 싶었다. 진아가 가진 꽃의 씨앗은 꽃을 심고나면 정확히 1년후에 꽃이 피므

www.acmicpc.net

 

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

[1138] 한 줄로 서기  (0) 2023.07.04
[2477] 참외밭  (0) 2023.07.03
[BOJ]14497. 주난의 난(難)  (0) 2022.08.16
[BOJ]12851. 숨바꼭질 2  (0) 2022.08.09
[BOJ]1189. 컴백홈  (0) 2022.08.04

문제:

어떤 두 자연수에 공통인 약수들 중에서 가장 큰 수를 최대공약수라고 하고, 두 자연수의 공통인 배수들 중에서 가장 작은 수를 최소공배수라고 한다.

예를 들어, 두 자연수 12와 90의 최대공약수는 6이며, 최소공배수는 180이다.

이와 반대로 두 개의 자연수 A, B가 주어졌을 때, A를 최대공약수로, B를 최소공배수로 하는 두 개의 자연수를 구할 수 있다. 그러나, 이러한 두 개의 자연수 쌍은 여러 개 있을 수 있으며, 또한 없을 수도 있다. 

예를 들어, 최대공약수가 6이며 최소공배수가 180인 두 정수는 위의 예에서와 같이 12와 90일 수도 있으며, 30과 36, 18과 60, 혹은 6과 180일 수도 있다. 그러나, 최대공약수가 6이며 최소공배수가 20인 두 자연수는 있을 수 없다.

두 개의 자연수가 주어졌을 때, 이 두 수를 최대공약수와 최소공배수로 하는 두 개의 자연수를 구하는 프로그램을 작성하시오. 

입력:

첫째 줄에 두 개의 자연수가 빈칸을 사이에 두고 주어진다. 첫 번째 수는 어떤 두 개의 자연수의 최대공약수이고, 두 번째 수는 그 자연수들의 최소공배수이다. 입력되는 두 자연수는 2 이상 100,000,000 이하이다.

출력:

첫째 줄에는 입력되는 두 자연수를 최대공약수와 최소공배수로 하는 두 개의 자연수를 크기가 작은 수부터 하나의 공백을 사이에 두고 출력한다. 입력되는 두 자연수를 최대공약수와 최소공배수로 하는 두 개의 자연수 쌍이 여러 개 있는 경우에는 두 자연수의 합이 최소가 되는 두 수를 출력한다.

풀이방법:

 어떤 두 자연수를 A, B라고 하고, 최대공약수를 G,  최소공배수를 L이라고 하자. 최대공약수는 공통인 약수들 중에서 가장 큰 수이기 때문에 두 자연수 A, B는 A=aG, B=bG와 같이 표현할 수 있다. 그리고 최소공배수는 두 자연수의 공통인 배수들 중에서 가장 작은 수이므로 L=abG라고 표현할 수 있다. (aG와 bG의 공통의 배수이기 때문)

 따라서 최대공약수와 최소공배수 간의 관계는 ab= L/G라고 할 수 있다. A와 B를 찾기 위해 G는 이미 알고 있으므로 가능한 a와 b를 구하도록 한다. 즉, ab의 약수들을 찾으면 되는 문제다.

 ab의 약수들을 기반으로 A와 B 값을 구한 뒤에 문제의 조건처럼 두 자연수의 합이 최소가 되도록 정렬을 수행하여 두 수를 찾는다. 

1
2
3
4
5
6
7
8
9
10
11
12
import math
 
G, L = map(int,input().split())
ab = L//G
 
answers = []
for n in range(1,int(math.sqrt(ab))+1):
    if ab%n==0 and math.gcd(ab//n, n)==1:
        A, B = n*G, ab//n*G
        answers.append((A,B))
 
print(*sorted(answers, key = lambda x: x[1]-x[0])[0])
cs

문제링크:

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

 

2436번: 공약수

첫째 줄에 두 개의 자연수가 빈칸을 사이에 두고 주어진다. 첫 번째 수는 어떤 두 개의 자연수의 최대공약수이고, 두 번째 수는 그 자연수들의 최소공배수이다. 입력되는 두 자연수는 2 이상 100,0

www.acmicpc.net

 

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

[BOJ]1268. 임시 반장 정하기  (0) 2022.05.10
[BOJ] 2511. 카드놀이  (0) 2022.05.03
[BOJ]6976. 절사평균  (0) 2022.04.26
[BOJ] 2303. 숫자 게임  (0) 2022.04.21
[BOJ]2635. 수 이어가기  (0) 2022.04.19

문제:

다음과 같은 규칙에 따라 수들을 만들려고 한다.

  1. 첫 번째 수로 양의 정수가 주어진다.
  2. 두 번째 수는 양의 정수 중에서 하나를 선택한다.
  3. 세 번째부터 이후에 나오는 모든 수는 앞의 앞의 수에서 앞의 수를 빼서 만든다. 예를 들어, 세 번째 수는 첫 번째 수에서 두 번째 수를 뺀 것이고, 네 번째 수는 두 번째 수에서 세 번째 수를 뺀 것이다.
  4. 음의 정수가 만들어지면, 이 음의 정수를 버리고 더 이상 수를 만들지 않는다.

첫 번째 수로 100이 주어질 때, 두 번째 수로 60을 선택하여 위의 규칙으로 수들을 만들면 7개의 수들 100, 60, 40, 20, 20 , 0, 20이 만들어진다. 그리고 두 번째 수로 62를 선택하여 위의 규칙으로 수들을 만들면 8개의 수들 100, 62, 38, 24, 14, 10, 4, 6이 만들어진다. 위의 예에서 알 수 있듯이, 첫 번째 수가 같더라도 두 번째 수에 따라서 만들어지는 수들의 개수가 다를 수 있다.

입력으로 첫 번째 수가 주어질 때, 이 수에서 시작하여 위의 규칙으로 만들어지는 최대 개수의 수들을 구하는 프로그램을 작성하시오. 최대 개수의 수들이 여러 개일 때, 그중 하나의 수들만 출력하면 된다.

입력:

첫 번째 수가 주어진다. 이 수는 30,000 보다 같거나 작은 양의 정수이다.

출력:

첫 번째 줄에는 입력된 첫 번째 수로 시작하여 위의 규칙에 따라 만들 수 있는 수들의 최대 개수를 출력한다.

둘째 줄에 그 최대 개수의 수들을 차례대로 출력한다. 이들 수 사이에는 빈칸을 하나씩 둔다.

풀이방법:

 주어질 수 있는 첫 번째 수가 크지 않기 때문에 브루트 포스 방법으로 모든 케이스를 고려하여 해결하면 된다. 1부터 N까지 반복하여 두 번째 수를 결정하고 3번, 4번의 과정을 진행한다. 4번으로 인해 더 이상 수를 만들지 않을 때마다 생성한 수들의 갯수를 비교하여 이전 케이스보다 큰 경우에만 기록하도록 한다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
= int(input())
answer = []
# N=1 일 때
for i in range(1,N+1):
    first = N
    second = i
    tmp = [N, i]
    while True:
        next_ = first - second
        if next_ >= 0:
            tmp.append(next_)
            first, second = second, next_
        else:
            if len(tmp) > len(answer):
                answer = tmp
            break
print(len(answer))
print(*answer)
cs

문제링크:

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

 

2635번: 수 이어가기

첫 번째 수가 주어진다. 이 수는 30,000 보다 같거나 작은 양의 정수이다.

www.acmicpc.net

 

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

[BOJ]6976. 절사평균  (0) 2022.04.26
[BOJ] 2303. 숫자 게임  (0) 2022.04.21
[BOJ]2596. 비밀편지  (0) 2022.04.14
[BOJ]2615. 오목  (0) 2022.04.12
[BOJ]2628. 종이자르기  (0) 2022.04.07

문제:

오목은 바둑판에 검은 바둑알과 흰 바둑알을 교대로 놓아서 겨루는 게임이다. 바둑판에는 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

문제:

아래 <그림 1>과 같이 직사각형 모양의 종이가 있다. 이 종이는 가로방향과 세로 방향으로 1㎝마다 점선이 그어져 있다. 가로 점선은 위에서 아래로 1번부터 차례로 번호가 붙어 있고, 세로 점선은 왼쪽에서 오른쪽으로 번호가 붙어 있다.

<그림 1>

점선을 따라 이 종이를 칼로 자르려고 한다. 가로 점선을 따라 자르는 경우는 종이의 왼쪽 끝에서 오른쪽 끝까지, 세로 점선인 경우는 위쪽 끝에서 아래쪽 끝까지 한 번에 자른다. 예를 들어, <그림 1>의 가로 길이 10㎝이고 세로 길이 8㎝인 종이를 3번 가로 점선, 4번 세로 점선, 그리고 2번 가로 점선을 따라 자르면 <그림 2>와 같이 여러 개의 종이 조각으로 나뉘게 된다. 이때 가장 큰 종이 조각의 넓이는 30㎠이다.

<그림 2>

입력으로 종이의 가로 세로 길이, 그리고 잘라야할 점선들이 주어질 때, 가장 큰 종이 조각의 넓이가 몇 ㎠인지를 구하는 프로그램을 작성하시오.

입력:

첫줄에는 종이의 가로와 세로의 길이가 차례로 자연수로 주어진다. 가로와 세로의 길이는 최대 100㎝이다. 둘째 줄에는 칼로 잘라야하는 점선의 개수가 주어진다. 셋째 줄부터 마지막 줄까지 한 줄에 점선이 하나씩 아래와 같은 방법으로 입력된다. 가로로 자르는 점선은 0과 점선 번호가 차례로 주어지고, 세로로 자르는 점선은 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
width, height = map(int, input().split())
= int(input())
horizon, vertical = [], []
for _ in range(n):
    com, pos = map(int,input().split())
    if com==0:
        horizon.append(pos)
    else:
        vertical.append(pos)
horizon.sort()
vertical.sort()
horizon.append(height)
vertical.append(width)
answer = 0 
for i, h in enumerate(horizon):
    if i==0:
        h_diff = h
    else:
        h_diff = h - horizon[i-1]
    for j, v in enumerate(vertical):
        if j==0:
            v_diff = v
        else:
            v_diff = v - vertical[j-1]
        answer = max(answer, h_diff*v_diff)
print(answer)
cs

문제링크:

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

 

2628번: 종이자르기

첫줄에는 종이의 가로와 세로의 길이가 차례로 자연수로 주어진다. 가로와 세로의 길이는 최대 100㎝이다. 둘째 줄에는 칼로 잘라야하는 점선의 개수가 주어진다. 셋째 줄부터 마지막 줄까지 한

www.acmicpc.net

 

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

[BOJ]2596. 비밀편지  (0) 2022.04.14
[BOJ]2615. 오목  (0) 2022.04.12
[BOJ]9205. 맥주 마시면서 걸어가기  (0) 2022.04.05
[BOJ]1439. 뒤집기  (0) 2022.03.31
[BOJ]2023. 신기한 소수  (0) 2022.03.29

문제:

영선이는 숫자가 쓰여 있는 직사각형 종이를 가지고 있다. 종이는 1×1 크기의 정사각형 칸으로 나누어져 있고, 숫자는 각 칸에 하나씩 쓰여 있다. 행은 위에서부터 아래까지 번호가 매겨져 있고, 열은 왼쪽부터 오른쪽까지 번호가 매겨져 있다.

영선이는 직사각형을 겹치지 않는 조각으로 자르려고 한다. 각 조각은 크기가 세로나 가로 크기가 1인 직사각형 모양이다. 길이가 N인 조각은 N자리 수로 나타낼 수 있다. 가로 조각은 왼쪽부터 오른쪽까지 수를 이어 붙인 것이고, 세로 조각은 위에서부터 아래까지 수를 이어붙인 것이다.

아래 그림은 4×4 크기의 종이를 자른 한 가지 방법이다.

각 조각의 합은 493 + 7160 + 23 + 58 + 9 + 45 + 91 = 7879 이다.

종이를 적절히 잘라서 조각의 합을 최대로 하는 프로그램을 작성하시오.

입력:

첫째 줄에 종이 조각의 세로 크기 N과 가로 크기 M이 주어진다. (1 ≤ N, M ≤ 4)

둘째 줄부터 종이 조각이 주어진다. 각 칸에 쓰여 있는 숫자는 0부터 9까지 중 하나이다.

출력:

영선이가 얻을 수 있는 점수의 최댓값을 출력한다.

풀이방법:

 비트마스킹을 사용하여 해당 문제를 풀었다. N*M의 크기의 직사각형을 0,1의 비트마스킹으로 표현한다. 이 때 0은 가로로 연결되는 경우를 의미하고, 1은 세로로 연결되는 경우를 의미하게 된다.

 주어진 케이스에 대해 가로와 각각 따로 계산을 수행하도록 한다. 가로는 idx가 0인 경우에 대해서만 이어붙이며 값을 누적시키도록 한다. 반대로 세로는 idx가 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
from itertools import product
 
h, w = map(int, input().split())
mat = []
for i in range(h):
    mat.append(list(map(int,list(input()))))
 
idxs = product(range(2),repeat=h*w)
 
ans = 0
for idx in idxs:
    tmp = 0
    for i in range(h):
        sum_ = 0
        for j in range(w):
            k = i*w+j
            if idx[k]==0:
                sum_ = 10*sum_+mat[i][j]
            else:
                tmp+=sum_
                sum_ = 0
        if sum_!=0:
            tmp+=sum_
    for i in range(w):
        sum_ = 0
        for j in range(h):
            k = i+j*w
            if idx[k]==1:
                sum_ = 10*sum_+mat[j][i]
            else:
                tmp+=sum_
                sum_ = 0
        if sum_!=0:
            tmp+=sum_
    if tmp > ans:
        ans = tmp
print(ans)
cs

문제링크:

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

 

14391번: 종이 조각

영선이는 숫자가 쓰여 있는 직사각형 종이를 가지고 있다. 종이는 1×1 크기의 정사각형 칸으로 나누어져 있고, 숫자는 각 칸에 하나씩 쓰여 있다. 행은 위에서부터 아래까지 번호가 매겨져 있고,

www.acmicpc.net

 

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

[BOJ]20056. 마법사 상어와 파이어볼  (0) 2021.11.02
[BOJ]11058. 크리보드  (0) 2021.11.01
[BOJ] 2251. 물통  (0) 2021.10.28
[BOJ] 15988. 1, 2, 3 더하기  (0) 2021.10.25
[BOJ] 13023. ABCDE  (0) 2021.10.22

문제:

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

문제:

위와 같은 십자모양의 한 장의 카드에서, 네 모서리에 1 이상 9 이하의 숫자가 하나씩 씌여 있다. 이 네 개의 숫자 중에는 같은 숫자도 있을 수 있다.

모든 가능한 십자 카드가 주어질 때, 각각의 카드는 다음과 같은 '시계수'라는 번호를 가진다. 시계수는 카드의 숫자들을 시계 방향으로 읽어서 만들어지는 네 자리 수들 중에서 가장 작은 수이다. 위 그림의 카드는 시계방향으로 3227, 2273, 2732, 7322로 읽을 수 있으므로, 이 카드의 시계수는 가장 작은 수인 2273이다.

입력으로 주어진 카드의 시계수를 계산하여, 그 시계수가 모든 시계수들 중에서 몇 번째로 작은 시계수인지를 알아내는 프로그램을 작성하시오.

예를 들어서, 다음과 같은 십자 카드의 시계수는 1122이며, 이 시계수보다 작은 시계수들은 1111, 1112, 1113, 1114, 1115, 1116, 1117, 1118, 1119 뿐이므로 1122는 10번째로 작은 시계수다. (여기서 십자카드는 0 이 나타날 수 없으므로 1120은 시계수가 될 수 없다. 또한 1121 이 적혀있는 카드의 시계수는 1112이므로, 1121은 시계수가 될 수 없다.

입력:

입력은 한 줄로 이루어지며, 이 한 줄은 카드의 네 모서리에 씌여있는 1 이상 9 이하의 숫자 4개가 시계 방향으로 입력된다. 각 숫자 사이에는 빈칸이 하나 있다.

출력:

입력된 카드의 시계수가 모든 시계수들 중에서 몇 번째로 작은 시계수인지를 출력한다.

풀이방법:

 1111부터 시작해서 주어진 수의 시계수까지 하나씩 다 구하면서 몇 번째인지 출력하도록 한다.

우선 입력된 카드의 시계수를 구한 뒤에 1111부터 해당 시계수까지 while로 반복한다. 이 때, 1120, 1121와 같이 시계수가 아닌 경우도 있기 때문에 해당 경우는 조건문을 사용하여 제외하도록 한다. 또한 회전연산을 쉽게 하기 위해 collections에 있는 deque의 rotate를 사용했다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from collections import deque
find_ = deque(map(int,input().split()))
 
def find_clock_num(number):
    find_ = deque(number)
    clock_number = 10000
    for _ in range(4):
        now = find_[0]*1000+find_[1]*100+find_[2]*10+find_[3]*1
        if now < clock_number:
            clock_number = now
        find_.rotate(1)
    return clock_number
 
clock_number = find_clock_num(find_)
    
answer = 0
start = 1111
while start<=clock_number:
    if find_clock_num(list(map(int,list(str(start))))) == start:
        answer+=1
    start+=1
print(answer)
cs

문제링크:

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

 

2659번: 십자카드 문제

입력은 한 줄로 이루어지며, 이 한 줄은 카드의 네 모서리에 씌여있는 1 이상 9 이하의 숫자 4개가 시계 방향으로 입력된다. 각 숫자 사이에는 빈칸이 하나 있다.

www.acmicpc.net

 

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

[BOJ] 15658. 연산자 끼워넣기 (2)  (0) 2021.10.20
[BOJ] 17140. 이차원 배열과 연산  (0) 2021.10.19
[BOJ] 2668. 숫자고르기  (0) 2021.10.15
[BOJ] 16918. 봄버맨  (0) 2021.10.14
[BOJ] 16236. 아기 상어  (0) 2021.10.13

문제:

스타트링크의 사무실은 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

문제:

폴리오미노란 크기가 1×1인 정사각형을 여러 개 이어서 붙인 도형이며, 다음과 같은 조건을 만족해야 한다.

  • 정사각형은 서로 겹치면 안 된다.
  • 도형은 모두 연결되어 있어야 한다.
  • 정사각형의 변끼리 연결되어 있어야 한다. 즉, 꼭짓점과 꼭짓점만 맞닿아 있으면 안 된다.

정사각형 4개를 이어 붙인 폴리오미노는 테트로미노라고 하며, 다음과 같은 5가지가 있다.

아름이는 크기가 N×M인 종이 위에 테트로미노 하나를 놓으려고 한다. 종이는 1×1 크기의 칸으로 나누어져 있으며, 각각의 칸에는 정수가 하나 쓰여 있다.

테트로미노 하나를 적절히 놓아서 테트로미노가 놓인 칸에 쓰여 있는 수들의 합을 최대로 하는 프로그램을 작성하시오.

테트로미노는 반드시 한 정사각형이 정확히 하나의 칸을 포함하도록 놓아야 하며, 회전이나 대칭을 시켜도 된다.

입력:

첫째 줄에 종이의 세로 크기 N과 가로 크기 M이 주어진다. (4 ≤ N, M ≤ 500)

둘째 줄부터 N개의 줄에 종이에 쓰여 있는 수가 주어진다. i번째 줄의 j번째 수는 위에서부터 i번째 칸, 왼쪽에서부터 j번째 칸에 쓰여 있는 수이다. 입력으로 주어지는 수는 1,000을 넘지 않는 자연수이다.

출력:

첫째 줄에 테트로미노가 놓인 칸에 쓰인 수들의 합의 최댓값을 출력한다.

풀이방법:

 정사각형 4개를 이어 붙인 폴리오미노인 테트로미노는 회전과 대칭을 포함해도 경우의 수가 많지 않다. 따라서 모든 경우의 수를 포함하고 있는 shape_list를 만든 후에 모든 점마다 테트로미노를 하나씩 넣어보며 가장 최대가 되는 경우를 찾는다.

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
shape_list = [
    [(0,1),(0,2),(0,3)],
    [(1,0),(2,0),(3,0)],
    [(0,1),(1,0),(1,1)],
    [(1,0),(2,0),(2,1)],
    [(1,0),(0,1),(0,2)],
    [(0,1),(1,1),(2,1)],
    [(0,1),(0,2),(-1,2)],
    [(1,0),(2,0),(2,-1)],
    [(0,1),(0,2),(1,2)],
    [(0,1),(1,0),(2,0)],
    [(1,0),(1,1),(1,2)],
    [(1,0),(1,1),(2,1)],
    [(0,1),(-1,1),(-1,2)],
    [(0,1),(1,0),(-1,1)],
    [(0,1),(1,1),(1,2)],
    [(0,1),(1,1),(0,2)],
    [(0,1),(-1,1),(1,1)],
    [(0,1),(-1,1),(0,2)],
    [(-1,0),(1,0),(0,1)]
]
N, M = map(int,input().split())
 
papers = []
for _ in range(N):
    papers.append(list(map(int,input().split())))
    
answer= 0
for i in range(N):
    for j in range(M):
        for shape in shape_list:
            start = papers[i][j]
            
            for k in range(3):
                nx = i + shape[k][0]
                ny = j + shape[k][1]
                if 0<= nx < N and 0<=ny < M:
                    start+=papers[nx][ny]
            if answer < start:
                answer= start
print(answer)
cs

문제링크:

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

 

14500번: 테트로미노

폴리오미노란 크기가 1×1인 정사각형을 여러 개 이어서 붙인 도형이며, 다음과 같은 조건을 만족해야 한다. 정사각형은 서로 겹치면 안 된다. 도형은 모두 연결되어 있어야 한다. 정사각형의 변

www.acmicpc.net

 

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

[BOJ] 16236. 아기 상어  (0) 2021.10.13
[BOJ] 15683. 감시  (0) 2021.10.12
[BOJ]2458. 키 순서  (0) 2021.10.07
[BOJ] 21608. 상어 초등학교  (0) 2021.10.06
[BOJ] 10157. 자리배정  (0) 2021.10.05

+ Recent posts