문제:

한수는 캠프를 마치고 집에 돌아가려 한다. 한수는 현재 왼쪽 아래점에 있고 집은 오른쪽 위에 있다. 그리고 한수는 집에 돌아가는 방법이 다양하다. 단, 한수는 똑똑하여 한번 지나친 곳을 다시 방문하지는 않는다.

      cdef  ...f  ..ef  ..gh  cdeh  cdej  ...f 
      bT..  .T.e  .Td.  .Tfe  bTfg  bTfi  .Tde 
      a...  abcd  abc.  abcd  a...  a.gh  abc. 
거리 :  6     6     6     8     8    10    6

위 예제는 한수가 집에 돌아갈 수 있는 모든 경우를 나타낸 것이다. T로 표시된 부분은 가지 못하는 부분이다. 문제는 R x C 맵에 못가는 부분이 주어지고 거리 K가 주어지면 한수가 집까지도 도착하는 경우 중 거리가 K인 가짓수를 구하는 것이다.

입력:

첫 줄에 정수 R(1 ≤ R ≤ 5), C(1 ≤ C ≤ 5), K(1 ≤ K ≤ R×C)가 공백으로 구분되어 주어진다. 두 번째부터 R+1번째 줄까지는 R×C 맵의 정보를 나타내는 '.'과 'T'로 구성된 길이가 C인 문자열이 주어진다.

출력:

첫 줄에 거리가 K인 가짓수를 출력한다.

풀이방법:

 DFS를 사용해서 시작점에서 도착점까지 이동하고, 한 번의 이동마다 거리를 하나씩 늘린다. 도착점에 도달한 경우 거리가 K와 같다면 answer를 하나 증가시키고, 그렇지 않다면 다시 되돌아 오는 과정을 수행한다. '다시 되돌아 온다' 라는 행동을 하기 위해 visited 배열을 사용하고, 그 위치로 이동한 경우에는 해당 좌표의 값을 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
dx = [-10 , 10]
dy = [0-10 , 1]
 
from collections import deque
 
def dfs(x, y, count):
    global answer
    visited[x][y]=1
    if [x,y]==[0, C-1]:
        if count==K:
            answer+=1
        return
    for i in range(4):
        nx = x + dx[i]
        ny = y + dy[i]
        if 0<= nx < R and 0 <= ny < C  and visited[nx][ny]==0 and maps[nx][ny]!='T':
            visited[nx][ny]=1
            dfs(nx,ny,count+1)
            visited[nx][ny]=0
            
R, C, K = map(int,input().split())
maps = [list(input()) for _ in range(R)]
visited = [[0 for _ in range(C)] for _ in range(R)]
answer= 0
dfs(R-101)
print(answer)
cs

문제링크:

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

 

1189번: 컴백홈

첫 줄에 정수 R(1 ≤ R ≤ 5), C(1 ≤ C ≤ 5), K(1 ≤ K ≤ R×C)가 공백으로 구분되어 주어진다. 두 번째부터 R+1번째 줄까지는 R×C 맵의 정보를 나타내는 '.'과 'T'로 구성된 길이가 C인 문자열이 주어진다

www.acmicpc.net

 

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

[BOJ]14497. 주난의 난(難)  (0) 2022.08.16
[BOJ]12851. 숨바꼭질 2  (0) 2022.08.09
[BOJ]12869.뮤탈리스크  (0) 2022.08.02
[BOJ]2852. NBA 농구  (0) 2022.07.28
[BOJ]3474. 교수가 된 현우  (0) 2022.07.26

문제:

수빈이가 세상에서 가장 좋아하는 것은 소수이고, 취미는 소수를 가지고 노는 것이다. 요즘 수빈이가 가장 관심있어 하는 소수는 7331이다.

7331은 소수인데, 신기하게도 733도 소수이고, 73도 소수이고, 7도 소수이다. 즉, 왼쪽부터 1자리, 2자리, 3자리, 4자리 수 모두 소수이다! 수빈이는 이런 숫자를 신기한 소수라고 이름 붙였다.

수빈이는 N자리의 숫자 중에서 어떤 수들이 신기한 소수인지 궁금해졌다. N이 주어졌을 때, 수빈이를 위해 N자리 신기한 소수를 모두 찾아보자.

입력:

첫째 줄에 N(1 ≤ N ≤ 8)이 주어진다.

출력:

N자리 수 중에서 신기한 소수를 오름차순으로 정렬해서 한 줄에 하나씩 출력한다.

풀이방법:

 보통 일반적인 소수 문제의 경우에는 에라토스테네스의 체를 사용해서 소수인 수들을 모두 찾고 하는 것이 빠른 경우가 많으나, 이 문제의 경우에는 N = 8 인 경우에 수가 엄청 커지게 되고, 시간이 오래 걸리게 된다.

 따라서 이 문제의 경우에는 dfs를 사용해서 한자리씩 붙여 나가면서 소수를 판정하는 방식을 사용하도록 한다. 문제의 특징으로 인해 75가 소수가 아니므로, 그 뒤는 판정할 필요가 없기 때문이다. dfs의 종료 조건은 숫자의 길이가 N이 될 때까지 진행한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
def check_prime(n):
    if n==1 or n==0:
        return 0
    for i in range(2int(n**0.5)+1):
        if n%i==0:
            return 0
    return 1
 
def dfs(number, length):
    if length==n:
        print(number)
        return
    for i in range(10):
        tmp = number+str(i)
        if check_prime(int(tmp)):
            dfs(tmp,length+1)
    
 
= int(input())
 
dfs('',0)
cs

문제링크:

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

 

2023번: 신기한 소수

수빈이가 세상에서 가장 좋아하는 것은 소수이고, 취미는 소수를 가지고 노는 것이다. 요즘 수빈이가 가장 관심있어 하는 소수는 7331이다. 7331은 소수인데, 신기하게도 733도 소수이고, 73도 소수

www.acmicpc.net

 

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

[BOJ]9205. 맥주 마시면서 걸어가기  (0) 2022.04.05
[BOJ]1439. 뒤집기  (0) 2022.03.31
[BOJ]1052. 물병  (0) 2022.03.24
[BOJ]1004. 어린 왕자  (0) 2022.03.22
[BOJ]2252. 줄 세우기  (0) 2022.03.17

문제:

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

문제:

세로 R칸, 가로 C칸으로 된 표 모양의 보드가 있다. 보드의 각 칸에는 대문자 알파벳이 하나씩 적혀 있고, 좌측 상단 칸 (1행 1열) 에는 말이 놓여 있다.

말은 상하좌우로 인접한 네 칸 중의 한 칸으로 이동할 수 있는데, 새로 이동한 칸에 적혀 있는 알파벳은 지금까지 지나온 모든 칸에 적혀 있는 알파벳과는 달라야 한다. 즉, 같은 알파벳이 적힌 칸을 두 번 지날 수 없다.

좌측 상단에서 시작해서, 말이 최대한 몇 칸을 지날 수 있는지를 구하는 프로그램을 작성하시오. 말이 지나는 칸은 좌측 상단의 칸도 포함된다.

입력:

첫째 줄에 R과 C가 빈칸을 사이에 두고 주어진다. (1 ≤ R,C ≤ 20) 둘째 줄부터 R개의 줄에 걸쳐서 보드에 적혀 있는 C개의 대문자 알파벳들이 빈칸 없이 주어진다.

출력:

첫째 줄에 말이 지날 수 있는 최대의 칸 수를 출력한다.

풀이방법:

dfs를 사용해서 이 문제를 풀 수 있다. dfs는 다음과 같이 구성되어 있다.

 

1. 한 점으로부터 시작해 상하좌우를 탐색한다. (처음은 1행 1열)

2. 상하좌우를 탐색할 때, 아직 방문하지 않았고, 처음보는 알파벳이라면 그 방향으로 다시 dfs를 탐색한다.

3. dfs를 시작하는 순간마다. 현재까지 가지고 있는 알파벳 수를 기억해서 최대 몇칸을 지날 수 있는지 확인한다.

4. 더 이상 이동하지 못하는 경우에 한 dfs를 빠져나오게 되며, 방문 기록과 알파벳 탐색 기록을 지운다.

 

최종적으로 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
import sys
input = sys.stdin.readline
 
def dfs(x,y,tmp):
    global answer
    if answer < tmp:
        answer = tmp
    for i in range(4):
        nx = x + dx[i]
        ny = y + dy[i]
        if 0<=nx < R and 0 <=ny < C:
            if not history[ord(alphabet[nx][ny])-65and not visited[nx][ny]:
                history[ord(alphabet[nx][ny])-65= True
                visited[nx][ny] = 1
                dfs(nx,ny,tmp+1)
                visited[nx][ny] = 0
                history[ord(alphabet[nx][ny])-65= False
    
 
R,C = map(int,input().split())
alphabet = []
for _ in range(R):
    alphabet.append(list(input()))
visited = [[0 for _ in range(C)] for _ in range(R)]
dx = [-1,0,0,1]
dy = [0,-1,1,0]
 
history = [False]*26
visited[0][0= 1
history[ord(alphabet[0][0])-65= True
answer = 1
dfs(0,0,answer)
print(answer)
cs

문제링크:

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

 

1987번: 알파벳

세로 R칸, 가로 C칸으로 된 표 모양의 보드가 있다. 보드의 각 칸에는 대문자 알파벳이 하나씩 적혀 있고, 좌측 상단 칸 (1행 1열) 에는 말이 놓여 있다. 말은 상하좌우로 인접한 네 칸 중의 한 칸으

www.acmicpc.net

 

'Algorithm' 카테고리의 다른 글

[BOJ]11559. Puyo Puyo  (0) 2021.09.07
[BOJ]3190. 뱀  (0) 2021.08.19
[BOJ]1520. 내리막길  (0) 2021.08.17
[BOJ]14425. 문자열 집합  (0) 2021.06.24
[Programmers]Lv 1.완주하지 못한 선수  (0) 2019.02.17

문제:

두 종류의 부등호 기호 ‘<’와 ‘>’가 k개 나열된 순서열  A가 있다. 우리는 이 부등호 기호 앞뒤에 서로 다른 한 자릿수 숫자를 넣어서 모든 부등호 관계를 만족시키려고 한다. 예를 들어, 제시된 부등호 순서열 A가 다음과 같다고 하자.

A =>  < < < > < < > < >

부등호 기호 앞뒤에 넣을 수 있는 숫자는 0부터 9까지의 정수이며 선택된 숫자는 모두 달라야 한다. 아래는 부등호 순서열 A를 만족시키는 한 예이다. 

3 < 4 < 5 < 6 > 1 < 2 < 8 > 7 < 9 > 0

이 상황에서 부등호 기호를 제거한 뒤, 숫자를 모두 붙이면 하나의 수를 만들 수 있는데 이 수를 주어진 부등호 관계를 만족시키는 정수라고 한다. 그런데 주어진 부등호 관계를 만족하는 정수는 하나 이상 존재한다. 예를 들어 3456128790 뿐만 아니라 5689023174도 아래와 같이 부등호 관계 A를 만족시킨다. 

5 < 6 < 8 < 9 > 0 < 2 < 3 > 1 < 7 > 4

여러분은 제시된 k개의 부등호 순서를 만족하는 (k+1)자리의 정수 중에서 최댓값과 최솟값을 찾아야 한다. 앞서 설명한 대로 각 부등호의 앞뒤에 들어가는 숫자는 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }중에서 선택해야 하며 선택된 숫자는 모두 달라야 한다

입력:

첫 줄에 부등호 문자의 개수를 나타내는 정수 k가 주어진다. 그 다음 줄에는 k개의 부등호 기호가 하나의 공백을 두고 한 줄에 모두 제시된다. k의 범위는 2 ≤ k ≤ 9 이다. 

출력:

여러분은 제시된 부등호 관계를 만족하는 k+1 자리의 최대, 최소 정수를 첫째 줄과 둘째 줄에 각각 출력해야 한다. 단 아래 예(1)과 같이 첫 자리가 0인 경우도 정수에 포함되어야 한다. 모든 입력에 답은 항상 존재하며 출력 정수는 하나의 문자열이 되도록 해야 한다. 

풀이방법:

 처음에는 itertools의 permutation을 사용해서 풀려고 했으나, 메모리 초과가 발생했다. 아무래도 경우의 수가 엄청 많기 때문에 발생한 것 같았다.

 따라서 백트래킹(dfs)를 사용해서 효율적으로 구하려고 했다. visited 배열을 만들어서 사용한 숫자, 그렇지 않은 숫자를 구분했고, 빈 문자열로 시작했기 때문에 length==0이라는 조건을 넣어주게 되었다. is_possible 함수를 통해 부등호를 만족하는 조건의 숫자들을 구했으면 이를 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
def is_possible(i,op,j):
    if op == ">":
        return i > j
    else:
        return i < j
 
def dfs(length,can):
    global answer
    if length==n+1:
        answer.append(can)
        return
    for i in range(10):
        if not visited[i]:
            if length==0 or is_possible(can[-1],ie[length-1],str(i)):
                visited[i] = True
                dfs(length+1,can+str(i))
                visited[i] = False
                
n=int(input())
ie = input().split()
numbers  = list(range(10))
visited = [False]*10
answer = []
dfs(0,"")
print(answer[-1])
print(answer[0])
cs

문제링크:

www.acmicpc.net/problem/2529

 

2529번: 부등호

두 종류의 부등호 기호 ‘<’와 ‘>’가 k개 나열된 순서열  A가 있다. 우리는 이 부등호 기호 앞뒤에 서로 다른 한 자릿수 숫자를 넣어서 모든 부등호 관계를 만족시키려고 한다. 예를 들어, 제

www.acmicpc.net

 

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

[BOJ]1251. 단어 나누기  (0) 2021.02.02
[BOJ]1715. 카드 정렬하기  (0) 2021.01.28
[BOJ]2003. 수들의 합 2  (0) 2021.01.19
[BOJ]2661. 좋은 수열  (0) 2021.01.14
[BOJ]15711. 환상의 짝꿍  (0) 2021.01.12

문제:

숫자 1, 2, 3으로만 이루어지는 수열이 있다. 임의의 길이의 인접한 두 개의 부분 수열이 동일한 것이 있으면, 그 수열을 나쁜 수열이라고 부른다. 그렇지 않은 수열은 좋은 수열이다.

다음은 나쁜 수열의 예이다.

  • 33
  • 32121323
  • 123123213

다음은 좋은 수열의 예이다.

  • 2
  • 32
  • 32123
  • 1232123

길이가 N인 좋은 수열들을 N자리의 정수로 보아 그중 가장 작은 수를 나타내는 수열을 구하는 프로그램을 작성하라. 예를 들면, 1213121과 2123212는 모두 좋은 수열이지만 그 중에서 작은 수를 나타내는 수열은 1213121이다.

입력:

입력은 숫자 N하나로 이루어진다. N은 1 이상 80 이하이다.

출력:

첫 번째 줄에 1, 2, 3으로만 이루어져 있는 길이가 N인 좋은 수열들 중에서 가장 작은 수를 나타내는 수열만 출력한다. 수열을 이루는 1, 2, 3들 사이에는 빈칸을 두지 않는다.

풀이방법:

 dfs를 사용해서 수열에 숫자 하나씩을 붙여나가면서 좋은 수열인지 확인하고, 좋은 수열이라면 다시 붙이고, 그렇지 않다면 다른 숫자를 붙이는 방법을 사용하도록 한다.

 좋은 수열들 중 가장 작은 값을 찾아야 한다. 따라서 작은 값이 되기 위해서는 1로 시작해야 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import sys
def good_permutation(number):
    for i in range(1,len(number)//2+1):
        if number[-i:]==number[-2*i:-i]:
            return False
    return True
 
def dfs(number,idx):
    if idx == n:
        print(number)
        sys.exit()
    
    for c in ['1','2','3']:
        if good_permutation(number+c):
            dfs(number+c,idx+1)
        
= int(input())
number = '1'
dfs(number,1)
cs

문제링크:

www.acmicpc.net/problem/2661

 

2661번: 좋은수열

첫 번째 줄에 1, 2, 3으로만 이루어져 있는 길이가 N인 좋은 수열들 중에서 가장 작은 수를 나타내는 수열만 출력한다. 수열을 이루는 1, 2, 3들 사이에는 빈칸을 두지 않는다.

www.acmicpc.net

 

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

[BOJ]2529. 부등호  (0) 2021.01.26
[BOJ]2003. 수들의 합 2  (0) 2021.01.19
[BOJ]15711. 환상의 짝꿍  (0) 2021.01.12
[BOJ]14938. 서강그라운드  (0) 2021.01.07
[BOJ]1922. 네트워크 연결  (0) 2021.01.05

문제:

웅찬이는 근성이 대단한 도둑이다. 그래서 금고를 털 때, 모든 조합을 눌러본다. 예를 들어 비밀번호가 3글자 라는 사실을 알 때, 000, 001, 002, 003, … 998, 999의 모든 조합을 눌러본다. 그러나 웅찬이는 선견지명이 있어서 비밀번호에 어떤 숫자가 들어가는지 일부 알 수 있다. 예를 들어 3글자 비밀번호에 0이 들어감을 안다면 999 와 같이 0이 들어가지 않는 수는 가능성이 없다. 그러나 000, 012, 030과 같은 수는 가능하다. 비밀번호의 길이와 선견지명으로 알게된 비밀번호의 일부 숫자가 주어질 때, 모든 가능한 비밀번호의 개수를 출력하는 프로그램을 작성하시오.

입력:

첫줄에 비밀번호의 길이 n (1 ≤ n ≤ 7), 선견지명으로 알게된 비밀번호에 들어가는 수 m(0 ≤ m ≤ n) 이 주어지고, 둘째 줄에 m개의 서로 다른 숫자(0~9)가 주어진다.

출력:

가능한 모든 비밀번호의 개수를 출력한다.

풀이방법:

 처음에는 dfs를 활용한 백트래킹 방법으로 풀었다가 시간초과가 발생했다. 다른 방법을 생각해보던 중 수학적으로 풀 수 있음을 알게 되었다.

 따라서 포함배제의 원리를 사용해서 이 문제를 푼다. 문제에서 주어지는 n과 m만을 사용해서 풀수 있다.

m개의 수를 반드시 포함하는 경우의 수를 구하기 위해서 전체 가능한 경우의 수에서 m개의 수를 포함하지 않는 경우의 수를 빼는 것으로 구한다. 즉 다음과 같다.

 

비밀번호에 들어가는 수 m을 반드시 포함하는 비밀번호의 수 = 전체 비밀번호의 수 - m개의 수가 포함되지 않은 비밀번호의 수

 

전체 경우의 수는 10^n가 된다. m개의 수가 포함되지 않은 비밀번호의 수는 포함배제의 원리를 사용해서 구하도록 한다. 즉 구하는 식은 다음과 같이 된다.

 

answer = 10^n - mC1*9^n+mC2*8^n-mC3*7^n+.....

1
2
3
4
5
6
7
8
9
10
11
12
13
import math
 
def nCr(n,r):
    return int(math.factorial(n)/(math.factorial(n-r)*math.factorial(r)))
 
n, m = map(int,input().split())
numbers = list(map(int,input().split()))
answer = 0
count=10
for i in range(m+1):
    answer+=((-1)**i)*pow(count,n)*nCr(m,i)
    count-=1
print(answer)
cs

*2022-02-05*

EOFError가 발생해서 이유를 알아보니 m이 0인 경우에는 numbers 입력을 받지 않아야 했다. 따라서 다음과 같이 조건문을 추가한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import math
 
def nCr(n,r):
    return int(math.factorial(n)/(math.factorial(n-r)*math.factorial(r)))
 
n, m = map(int,input().split())
if m!=0:
    numbers = list(map(int,input().split()))
else:
    numbers = []
answer = 0
count=10
for i in range(m+1):
    answer+=((-1)**i)*pow(count,n)*nCr(m,i)
    count-=1
print(answer)
cs

문제링크:

www.acmicpc.net/problem/13908

 

13908번: 비밀번호

첫 번째 예제의 경우 가능한 비밀번호의 조합은 07, 17, 27, 37, 47, 57, 67, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 87, 97이다. 두 번째 예제의 경우 가능한 비밀번호의 조합은 34, 43이다.

www.acmicpc.net

 

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

[BOJ]1922. 네트워크 연결  (0) 2021.01.05
[BOJ]1613. 역사  (0) 2020.12.31
[BOJ]11723. 집합  (0) 2020.12.24
[BOJ]1527. 금민수의 개수  (0) 2020.12.22
[BOJ]7453. 합이 0인 네 정수  (0) 2020.12.10

문제:

스도쿠는 18세기 스위스 수학자가 만든 '라틴 사각형'이랑 퍼즐에서 유래한 것으로 현재 많은 인기를 누리고 있다. 이 게임은 아래 그림과 같이 가로, 세로 각각 9개씩 총 81개의 작은 칸으로 이루어진 정사각형 판 위에서 이뤄지는데, 게임 시작 전 몇 몇 칸에는 1부터 9까지의 숫자 중 하나가 쓰여 있다.

나머지 빈 칸을 채우는 방식은 다음과 같다.

1. 각각의 가로줄과 세로줄에는 1부터 9까지의 숫자가 한 번씩만 나타나야 한다.

2. 굵은 선으로 구분되어 있는 3x3 정사각형 안에도 1부터 9까지의 숫자가 한 번씩만 나타나야 한다.

위의 예의 경우, 첫재 줄에는 1을 제외한 나머지 2부터 9까지의 숫자들이 이미 나타나 있으므로 첫째 줄 빈칸에는 1이 들어가야 한다.

또한 위쪽 가운데 위치한 3x3 정사각형의 경우에는 3을 제외한 나머지 숫자들이 이미 쓰여있으므로 가운데 빈칸에는 3이 들어가야 한다.

이와 같이 빈 칸을 차례로 채워 가면 다음과 같은 최종 결과를 얻을 수 있다.

 

게임 시작 전 스도쿠 판에 쓰여 있는 숫자들의 정보가 주어질 때 모든 빈 칸이 채워진 최종 모습을 출력하는 프로그램을 작성하시오.

입력:

아홉 줄에 걸쳐 한 줄에 9개씩 게임 시작 전 스도쿠판 각 줄에 쓰여 있는 숫자가 한 칸씩 띄워서 차례로 주어진다. 스도쿠 판의 빈 칸의 경우에는 0이 주어진다. 스도쿠 판을 규칙대로 채울 수 없는 경우의 입력은 주어지지 않는다.

출력:

모든 빈 칸이 채워진 스도쿠 판의 최종 모습을 아홉줄에 걸쳐 한 줄에 9개씩 한 칸씩 띄워서 출력한다.

스도쿠 판을 채우는 방법이 여럿인 경우는 그 중 하나만을 출력한다.

풀이방법:

pypy3로 통과한 코드입니다. 0인 점에서 가능한 모든 경우의 수를 탐색하면서 백트래킹을 수행해 python3에서 통과하지 못한듯 합니다.

우선 sudoku 배열에 입력을 모두 받아준 뒤에 이를 순회하면서 0인 점을 찾아서 toDoList로 만들어 준다.

이를 인덱스로 접근하는 재귀 함수 check에 넣어주면서 백트래킹을 수행한다.

isPromising를 통해서 가능한 경우의 수를 구해주도록 했다. set 자료형과 차집합을 이용해서 경우의 수를 구하도록 했다. 이 경우의 수를 넣어보면서 dfs 방식으로 답을 구해주도록 한다.

인덱스가 끝까지 진행을 하면 sys.exit()로 바로 종료하도록 했다. (스도쿠 판을 규칙대로 채울 수 없는 경우의 입력은 주어지지 않으며, 여럿인 경우여도 하나만 출력하면 되기 때문이다.)

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
import sys
 
sudoku = [list(map(int,sys.stdin.readline().split())) for _ in range(9)]
 
toDoList = []
for i in range(9):
    for j in range(9):
        if sudoku[i][j] == 0:
            toDoList.append((i,j))
            
def isPromising(i,j):
    numbers = set(range(1,10))
    numbers -= set(sudoku[i])
    numbers -= set([sudoku[t][j] for t in range(9)])
    numbers -= set([sudoku[p][q] for p in range(3*(i//3),3*(i//3+1))
                    for q in range(3*(j//3),3*(j//3+1))])
    return numbers
 
def check(x):
    if x == len(toDoList):
        for row in sudoku:
            print(*row)
        sys.exit()
    else:
        i,j = toDoList[x]
        promising = isPromising(i,j)
    
    for case in promising:
        sudoku[i][j] = case
        check(x+1)
        sudoku[i][j] = 0
check(0) # 인덱스로 접근
cs

문제링크:

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

 

2580번: 스도쿠

스도쿠는 18세기 스위스 수학자가 만든 '라틴 사각형'이랑 퍼즐에서 유래한 것으로 현재 많은 인기를 누리고 있다. 이 게임은 아래 그림과 같이 가로, 세로 각각 9개씩 총 81개의 작은 칸으로 이루

www.acmicpc.net

 

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

[BOJ]2493. 탑  (0) 2020.08.06
[BOJ]19532. 수학은 비대면강의입니다.  (0) 2020.08.04
[BOJ]17362  (0) 2020.07.28
[BOJ]18258. 큐2  (0) 2020.07.23
[BOJ]4963. 섬의 개수  (0) 2020.07.21

문제:

세로 R칸,가로 C칸으로 된 표 모양의 보드가 있다. 보드의 각 칸에는 대문자 알파벳이 하나씩 적혀 있고, 좌측 상단 칸(1행 1열)에는 말이 놓여 있다.

말은 상하좌우로 인접한 네 칸 중의 한 칸으로 이동할 수 있는데, 새로 이동한 칸에 적혀 있는 알파벳은 지금까지 지나온 모든 칸에 적혀 있는 알파벳과는 달라야 한다. 즉, 같은 알파벳이 적힌 칸을 두 번 지날 수 없다.

좌측 상단에서 시작해서, 말이 최대한 몇 칸을 지날 수 있는지를 구하는 프로그램을 작성하시오. 말이 지나는 칸은 좌측 상단의 칸도 포함된다.

입력:

첫째 줄에 R과 C가 빈칸을 사이에 두고 주어진다. (1<=R,C<=20)둘째 줄부터 R개의 줄에 걸쳐서 보드에 적혀 있는 C개의 대문자 알파벳들이 빈칸 없이 주어진다.

출력:

첫째 줄에 말이 지날 수 있는 최대의 칸 수를 출력한다.

풀이방법:

제일 많이 파고 들어가야 하는 문제이므로 DFS와 백트래킹을 사용하는 것이 적합하다. 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
def go(board,check,x,y):
    ans=0
    for i in range(4):
        nx=x+dx[i]
        ny=y+dy[i]
        if 0<=nx<len(board) and 0<=ny<len(board[0]):
            if check[ord(board[nx][ny])-65]==False:
                check[ord(board[nx][ny])-65]=True
                count=go(board,check,nx,ny)
                if ans < count:
                    ans = count
                check[ord(board[nx][ny])-65]=False
    return ans+1
 
 
r,c=map(int,input().split())
board=[]
for i in range(r):
    board.append(list(input()))
dx=[0,0,1,-1]
dy=[1,-1,0,0]
answer=[]
check=[False]*26
x,y=0,0
check[ord(board[x][y])-65]=True
print(go(board,check,x,y))
cs

문제링크:

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

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

[Programmers]2017 Kakao.캐시  (0) 2019.09.27
[Programmers]2017 Kakao. 뉴스 클러스터링  (0) 2019.09.26
[BOJ]1759. 암호 만들기  (0) 2019.09.24
[BOJ]14889. 스타트와 링크  (0) 2019.09.23
[BOJ]1697. 숨바꼭질  (0) 2019.09.22

문제:

 바로 어제 최백준 조교가 방 열쇠를 주머니에 넣은 채 깜빡하고 서울로 가 버리는 황당한 상황에 직면한 조교들은, 702호에 새로운 보안 시스템을 설치하기로 하였다. 이 보안 시스템은 열쇠가 아닌 암호로 동작하게 되어 있는 시스템이다.

 

 암호는 서로 다른 L개의 알파벳 소문자들로 구성되며 최소 한 개의 모음과 최소 두 개의 자음으로 구성되어 있다고 알려져 있다. 또한 정렬된 문자열을 선호하는 조교들의 성향으로 미루어 보아 암호를 이루는 알파벳이 암호에서 증가하는 순서로 배열되었을 것이라고 추측된다. 즉, abc는 가능성이 있는 암호이지만 bac는 그렇지 않다.

 

 새 보안 시스템에서 조교들이 암호로 사용했을 법한 문자의 종류는 C가지가 있다고 한다. 이 알파벳을 입수한 민식, 영식 형제는 조교들의 방에 침투하기 위해 암호를 추측해 보려고 한다. C개의 문자들이 모두 주어졌을 때, 가능성 있는 암호들을 모두 구하는 프로그램을 작성하시오.

 

입력:

첫째 줄에 두 정수 L, C가 주어진다. (3<=L<=C<=15) 다음 줄에는 C개의 문자들이 공백으로 구분되어 주어진다. 주어지는 문자들은 알파벳 소문자이며, 중복되는 것은 없다.

 

출력:

각 줄에 하나씩, 사전식으로 가능성 있는 암호를 모두 출력한다.

 

풀이 방법:

 재귀적인 방법으로 암호를 만들고, 이 암호가 옳은 암호인지 판단하는 check라는 함수를 만들었다. 암호를 만들다가 길이가 L이 된다면 check로 옳은 암호인지 판단을 하고 맞다면 출력, 아니면 끝내도록 했다.

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
l,c = map(int,input().split())
chrs=input().split()
chrs.sort()
 
def check(alphabet):
    ahdma=0
    wkdma=0
    for a in alphabet:
        if a in ['a','e','i','o','u']:
            ahdma+=1
        else:
            wkdma+=1
    return ahdma>=1 and wkdma>=2
            
 
def make(l,chrs,alphabet,idx):
    if len(alphabet)==l:
        if check(alphabet):
            print(alphabet)
        return
    if idx >=len(chrs):
        return
    ne=alphabet+chrs[idx]
    idx+=1
    make(l,chrs,ne,idx)
    make(l,chrs,alphabet,idx)
 
alphabet=''
idx=0
make(l,chrs,alphabet,idx)
cs

 

문제링크:

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

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

[Programmers]2017 Kakao. 뉴스 클러스터링  (0) 2019.09.26
[BOJ]1987. 알파벳  (0) 2019.09.25
[BOJ]14889. 스타트와 링크  (0) 2019.09.23
[BOJ]1697. 숨바꼭질  (0) 2019.09.22
[BOJ]2022. 사다리  (0) 2019.09.21

+ Recent posts