문제:

크기가 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

문제:

위와 같은 십자모양의 한 장의 카드에서, 네 모서리에 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

문제:

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

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

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

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

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

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

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

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

입력:

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

출력:

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

풀이방법:

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
dx = [-1,0,1,0]
dy = [0,1,0,-1]
 
def del_bomb(maps):
    while bombs:
        x,y= bombs.popleft()
        maps[x][y] = '.'
        for i in range(4):
            nx = x + dx[i]
            ny = y + dy[i]
            if 0<=nx<and 0<=ny<C:
                maps[nx][ny]='.'
def set_bomb(maps):
    for i in range(R):
        for j in range(C):
            if maps[i][j]=='.':
                maps[i][j] = 'O'
                
def find_bomb(maps):
    for i in range(R):
        for j in range(C):
            if maps[i][j]=='O':
                bombs.append((i,j))
 
from collections import deque
R, C, N = map(int,input().split())
maps = []
for _ in range(R):
    maps.append(list(input()))
    
time = 1
while time!=N:
    bombs = deque()
    find_bomb(maps)
    set_bomb(maps)
    time+=1
    if time==N:
        break
    del_bomb(maps)
    time+=1
        
 
for map_ in maps:
    print("".join(map_))
cs

문제링크:

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

 

16918번: 봄버맨

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

www.acmicpc.net

 

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

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

문제:

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

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

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

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

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

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

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

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

입력:

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

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

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

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

출력:

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

풀이방법:

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

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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
dx = [-1,0,1,0]
dy = [0,1,0,-1]
 
def eat_fish(maps,i,j):
    queue = [(i,j,0)]
    visited = [[0 for _ in range(N)] for _ in range(N)]
    visited[i][j] = 1
    fish = []
    while queue:
        next_ = []
        for q in queue:
            x,y,count = q
            for i in range(4):
                nx = x + dx[i]
                ny = y + dy[i]
                if 0<=nx < N and 0<=ny < N:
                    if not visited[nx][ny]:
                        if 0<= maps[nx][ny] <= size:
                            if maps[nx][ny]!=0 and maps[nx][ny] < size:
                                fish.append((nx,ny,count+1))
                            next_.append((nx,ny,count+1))
                            visited[nx][ny] = 1
        queue = next_
    if fish:
        fish.sort(key=lambda x: (x[2],x[0],x[1]))
        return fish[0][0], fish[0][1],fish[0][2]
    else:
        return -1,-1,-1
            
= int(input())
 
maps = []
for _ in range(N):
    maps.append(list(map(int,input().split())))
    
ate  = maps.copy()
eat_count = 0
total_count = 0
time = 0
for i in range(N):
    for j in range(N):
        if maps[i][j]==9:
            x,y = i,j
            ate[x][y] = 0
        elif maps[i][j]:
            total_count+=1
 
size = 2
while True:
    nx,ny,d = eat_fish(maps,x,y)
    if nx==-1 and ny==-1:
        break
    else:
        maps[nx][ny] = 0
        time+=d
        eat_count+=1
    if eat_count==size:
        size+=1
        eat_count = 0
    x,y = nx,ny
print(time)
cs

문제링크:

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

 

16236번: 아기 상어

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

www.acmicpc.net

 

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

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

문제:

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

문제:

상어 초등학교에는 교실이 하나 있고, 교실은 N×N 크기의 격자로 나타낼 수 있다. 학교에 다니는 학생의 수는 N2명이다. 오늘은 모든 학생의 자리를 정하는 날이다. 학생은 1번부터 N2번까지 번호가 매겨져 있고, (r, c)는 r행 c열을 의미한다. 교실의 가장 왼쪽 윗 칸은 (1, 1)이고, 가장 오른쪽 아랫 칸은 (N, N)이다.

선생님은 학생의 순서를 정했고, 각 학생이 좋아하는 학생 4명도 모두 조사했다. 이제 다음과 같은 규칙을 이용해 정해진 순서대로 학생의 자리를 정하려고 한다. 한 칸에는 학생 한 명의 자리만 있을 수 있고, |r1 - r2| + |c1 - c2| = 1을 만족하는 두 칸이 (r1, c1)과 (r2, c2)를 인접하다고 한다.

  1. 비어있는 칸 중에서 좋아하는 학생이 인접한 칸에 가장 많은 칸으로 자리를 정한다.
  2. 1을 만족하는 칸이 여러 개이면, 인접한 칸 중에서 비어있는 칸이 가장 많은 칸으로 자리를 정한다.
  3. 2를 만족하는 칸도 여러 개인 경우에는 행의 번호가 가장 작은 칸으로, 그러한 칸도 여러 개이면 열의 번호가 가장 작은 칸으로 자리를 정한다.

예를 들어, N = 3이고, 학생 N2명의 순서와 각 학생이 좋아하는 학생이 다음과 같은 경우를 생각해보자.

가장 먼저, 4번 학생의 자리를 정해야 한다. 현재 교실의 모든 칸은 빈 칸이다. 2번 조건에 의해 인접한 칸 중에서 비어있는 칸이 가장 많은 칸인 (2, 2)이 4번 학생의 자리가 된다.

다음 학생은 3번이다. 1번 조건을 만족하는 칸은 (1, 2), (2, 1), (2, 3), (3, 2) 이다. 이 칸은 모두 비어있는 인접한 칸이 2개이다. 따라서, 3번 조건에 의해 (1, 2)가 3번 학생의 자리가 된다.

다음은 9번 학생이다. 9번 학생이 좋아하는 학생의 번호는 8, 1, 2, 3이고, 이 중에 3은 자리에 앉아있다. 좋아하는 학생이 가장 많이 인접한 칸은 (1, 1), (1, 3)이다. 두 칸 모두 비어있는 인접한 칸이 1개이고, 행의 번호도 1이다. 따라서, 3번 조건에 의해 (1, 1)이 9번 학생의 자리가 된다.

이번에 자리를 정할 학생은 8번 학생이다. (2, 1)이 8번 학생이 좋아하는 학생과 가장 많이 인접한 칸이기 때문에, 여기가 그 학생의 자리이다.

7번 학생의 자리를 정해보자. 1번 조건을 만족하는 칸은 (1, 3), (2, 3), (3, 1), (3, 2)로 총 4개가 있고, 비어있는 칸과 가장 많이 인접한 칸은 (2, 3), (3, 2)이다. 행의 번호가 작은 (2, 3)이 7번 학생의 자리가 된다.

이런식으로 학생의 자리를 모두 정하면 다음과 같다.

이제 학생의 만족도를 구해야 한다. 학생의 만족도는 자리 배치가 모두 끝난 후에 구할 수 있다. 학생의 만족도를 구하려면 그 학생과 인접한 칸에 앉은 좋아하는 학생의 수를 구해야 한다. 그 값이 0이면 학생의 만족도는 0, 1이면 1, 2이면 10, 3이면 100, 4이면 1000이다.

학생의 만족도의 총 합을 구해보자.

입력:

첫째 줄에 N이 주어진다. 둘째 줄부터 N2개의 줄에 학생의 번호와 그 학생이 좋아하는 학생 4명의 번호가 한 줄에 하나씩 선생님이 자리를 정할 순서대로 주어진다.

학생의 번호는 중복되지 않으며, 어떤 학생이 좋아하는 학생 4명은 모두 다른 학생으로 이루어져 있다. 입력으로 주어지는 학생의 번호, 좋아하는 학생의 번호는 N2보다 작거나 같은 자연수이다. 어떤 학생이 자기 자신을 좋아하는 경우는 없다.

출력:

첫째 줄에 학생의 만족도의 총 합을 출력한다.

풀이방법:

 문제의 조건에 따라 학생을 배치할 때, 고려해야 하는 점은 '빈칸'과 '친한친구의 수'다.

따라서 각 학생의 번호에 따른 선호도를 dict 형태로 정리한 후 첫 학생들부터 배치하기 시작한다. 학생들을 배치하기 위해 교실을 모두 탐색한다. 탐색한 자리가 빈 자리면 그 자리를 기준으로 빈 자리는 몇명인지, 배치하려고 하는 학생이 선호하는 학생의 수를 파악한다. 각 개수를 모두 세고 나면 조건 1, 2에 따라 좌표를 업데이트 한다. (조건 3은 이중 for로 인해 자동으로 고려된다.)

 모든 학생을 배치하고 난 뒤에는 다시 한 번 교실을 탐색하여 정해진 점수를 부여한다.

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
from collections import defaultdict
 
dx = [-1,0,1,0]
dy = [0,-1,0,1]
 
def check_room(num):
    x,y= -1,-1
    max_friend = -1
    max_empty = -1
    for i in range(N):
        for j in range(N):
            empty = 0
            friend = 0
            if room[i][j]==0:
                for k in range(4):
                    nx = i + dx[k]
                    ny = j + dy[k]
                    if 0<= nx < N and 0 <= ny < N:
                        if room[nx][ny]==0:
                            empty+=1
                        elif room[nx][ny] in students[num]:
                            friend+=1
                if friend >= max_friend:
                    if friend==max_friend:
                        if empty > max_empty:
                            x,y = i,j
                            max_friend = friend
                            max_empty = empty
                    else:
                        x,y = i,j
                        max_friend = friend
                        max_empty = empty
    return x, y
    
= int(input())
 
room = [[0 for _ in range(N)] for _ in range(N)]
students = defaultdict(list)
for _ in range(N*N):
    student = list(map(int,input().split()))
    students[student[0]] = student[1:]
    
for key in students.keys():
    x, y = check_room(key)
    room[x][y] = key
    
answer = 0
for i in range(N):
    for j in range(N):
        student = room[i][j]
        count = 0
        for k in range(4):
            nx = i + dx[k]
            ny = j + dy[k]
            if 0<= nx < N and 0 <= ny < N:
                if room[nx][ny] in students[student]:
                    count+=1
        if count:
            answer += pow(10,count-1)
print(answer)    
cs

문제링크:

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

 

21608번: 상어 초등학교

상어 초등학교에는 교실이 하나 있고, 교실은 N×N 크기의 격자로 나타낼 수 있다. 학교에 다니는 학생의 수는 N2명이다. 오늘은 모든 학생의 자리를 정하는 날이다. 학생은 1번부터 N2번까지 번호

www.acmicpc.net

 

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

[BOJ] 14500. 테트로미노  (0) 2021.10.08
[BOJ]2458. 키 순서  (0) 2021.10.07
[BOJ] 10157. 자리배정  (0) 2021.10.05
[BOJ] 1019. 책 페이지  (0) 2021.10.01
[BOJ]3020. 개똥벌레  (0) 2021.09.30

문제:

어떤 공연장에는 가로로 C개, 세로로 R개의 좌석이 C×R격자형으로 배치되어 있다. 각 좌석의 번호는 해당 격자의 좌표 (x,y)로 표시된다.

예를 들어보자. 아래 그림은 가로 7개, 세로 6개 좌석으로 구성된 7×6격자형 좌석배치를 보여주고 있다. 그림에서 각 단위 사각형은 개별 좌석을 나타내며, 그 안에 표시된 값 (x,y)는 해당 좌석의 번호를 나타낸다. 가장 왼쪽 아래의 좌석번호는 (1,1)이며, 가장 오른쪽 위 좌석의 번호는 (7,6)이다. 

이 공연장에 입장하기 위하여 많은 사람이 대기줄에 서있다. 기다리고 있는 사람들은 제일 앞에서부터 1, 2, 3, 4, . 순으로 대기번호표를 받았다. 우리는 대기번호를 가진 사람들에 대하여 (1,1)위치 좌석부터 시작하여 시계방향으로 돌아가면서 비어있는 좌석에 관객을 순서대로 배정한다. 이것을 좀 더 구체적으로 설명하면 다음과 같다.

먼저 첫 번째 사람, 즉 대기번호 1인 사람은 자리 (1,1)에 배정한다. 그 다음에는 위쪽 방향의 좌석으로 올라가면서 다음 사람들을 배정한다. 만일 더 이상 위쪽 방향으로 빈 좌석이 없으면 오른쪽으로 가면서 배정한다. 오른쪽에 더 이상 빈자리가 없으면 아래쪽으로 내려간다. 그리고 아래쪽에 더 이상 자리가 없으면 왼쪽으로 가면서 남은 빈 좌석을 배정한다. 이 후 왼쪽으로 더 이상의 빈 좌석이 없으면 다시 위쪽으로 배정하고, 이 과정을 모든 좌석이 배정될 때까지 반복한다. 

아래 그림은 7×6공연장에서 대기번호 1번부터 42번까지의 관객이 좌석에 배정된 결과를 보여주고 있다.

여러분은 공연장의 크기를 나타내는 자연수 C와 R이 주어져 있을 때, 대기 순서가 K인 관객에게 배정될 좌석 번호 (x,y)를 찾는 프로그램을 작성해야 한다. 

입력:

첫 줄에는 공연장의 격자 크기를 나타내는 정수 C와 R이 하나의 공백을 사이에 두고 차례대로 주어진다. 두 값의 범위는 5 ≤ C, R ≤ 1,000이다. 그 다음 줄에는 어떤 관객의 대기번호 K가 주어진다. 단 1 ≤ K ≤ 100,000,000이다.

출력:

입력으로 제시된 대기번호 K인 관객에게 배정될 좌석번호 (x,y)를 구해서 두 값, x와 y를 하나의 공백을 사이에 두고 출력해야 한다. 만일 모든 좌석이 배정되어 해당 대기번호의 관객에게 좌석을 배정할 수 없는 경우에는 0(숫자 영)을 출력해야 한다. 

풀이방법:

 이 문제처럼 회전하며 숫자를 할당하는 알고리즘을 달팽이 배열이라고 한다. 생각보다 자주 나오는 알고리즘인 것 같아서 숙지할 필요가 있는 것 같다.

 주어진 공연장에 숫자를 달팽이 배열로 배치한 후 공연장의 값을 모두 탐색하여 K에 해당하는 R, C의 값을 반환하도록 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
C, R = map(int,input().split())
C_, R_ = C, R
= int(input())
if K > R*C:
    print(0)
else:
    count = 1
    row, col = -10
    maps = [[0 for _ in range(C)] for _ in range(R)]
    inc = 1
    while R > 0 and  C > 0:
        for _ in range(R):
            row+=inc
            maps[row][col] = count
            count+=1
        R-=1
        C-=1
        for _ in range(C):
            col+=inc
            maps[row][col] = count
            count+=1
        inc*=-1
    for r in range(R_):
        for c in range(C_):
            if maps[r][c]==K:
                print(c+1,r+1)
cs

문제링크:

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

 

10157번: 자리배정

첫 줄에는 공연장의 격자 크기를 나타내는 정수 C와 R이 하나의 공백을 사이에 두고 차례대로 주어진다. 두 값의 범위는 5 ≤ C, R ≤ 1,000이다. 그 다음 줄에는 어떤 관객의 대기번호 K가 주어진다.

www.acmicpc.net

 

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

[BOJ]2458. 키 순서  (0) 2021.10.07
[BOJ] 21608. 상어 초등학교  (0) 2021.10.06
[BOJ] 1019. 책 페이지  (0) 2021.10.01
[BOJ]3020. 개똥벌레  (0) 2021.09.30
[BOJ]6593. 상범 빌딩  (0) 2021.09.29

문제:

수빈이는 A와 B로만 이루어진 영어 단어가 존재한다는 사실에 놀랐다. 대표적인 예로 AB (Abdominal의 약자), BAA (양의 울음 소리), AA (용암의 종류), ABBA (스웨덴 팝 그룹)이 있다.

이런 사실에 놀란 수빈이는 간단한 게임을 만들기로 했다. 두 문자열 S와 T가 주어졌을 때, S를 T로 바꾸는 게임이다. 문자열을 바꿀 때는 다음과 같은 두 가지 연산만 가능하다.

  • 문자열의 뒤에 A를 추가한다.
  • 문자열을 뒤집고 뒤에 B를 추가한다.

주어진 조건을 이용해서 S를 T로 만들 수 있는지 없는지 알아내는 프로그램을 작성하시오. 

입력:

첫째 줄에 S가 둘째 줄에 T가 주어진다. (1 ≤ S의 길이 ≤ 999, 2 ≤ T의 길이 ≤ 1000, S의 길이 < T의 길이)

출력:

S를 T로 바꿀 수 있으면 1을 없으면 0을 출력한다.

풀이방법:

 S를 T로 바꾸는 방법에 대해 찾는 것이 아니라 T에서 S로 그리디하게 되돌아가는 방법으로 만들 수 있는지 없는지 확인한다.

 두 가지 연산은 맨 뒤에 A가 추가되거나 B가 추가된다. 따라서 매번 T의 맨 끝에 따라 연산을 수행하도록 한다. 맨 마지막이 A라면 A만 떼어내고, B라면 B를 떼어내고 뒤집어서 새로 T를 만들어내도록 한다.

 T와 S의 길이가 같아졌을 때, S와 T가 같다면 1을 같지않다면 0을 출력한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
= input()
= input()
answer = False
while True:
    if len(S) == len(T):
        if S==T:
            answer = True
        break
    if T[-1]=='A':
        T = T[:-1]
    elif T[-1]=='B':
        T = T[:-1][::-1]
if answer:
    print(1)
else:
    print(0)
cs

문제링크:

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

 

12904번: A와 B

수빈이는 A와 B로만 이루어진 영어 단어가 존재한다는 사실에 놀랐다. 대표적인 예로 AB (Abdominal의 약자), BAA (양의 울음 소리), AA (용암의 종류), ABBA (스웨덴 팝 그룹)이 있다. 이런 사실에 놀란 수

www.acmicpc.net

 

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

[BOJ]3020. 개똥벌레  (0) 2021.09.30
[BOJ]6593. 상범 빌딩  (0) 2021.09.29
[BOJ]1722. 순열의 순서  (0) 2021.09.27
[BOJ]1351. 무한 수열  (0) 2021.09.24
[BOJ]1202. 보석 도둑  (0) 2021.09.23

문제:

1부터 N까지의 수를 임의로 배열한 순열은 총 N! = N×(N-1)×…×2×1 가지가 있다.

임의의 순열은 정렬을 할 수 있다. 예를 들어  N=3인 경우 {1, 2, 3}, {1, 3, 2}, {2, 1, 3}, {2, 3, 1}, {3, 1, 2}, {3, 2, 1}의 순서로 생각할 수 있다. 첫 번째 수가 작은 것이 순서상에서 앞서며, 첫 번째 수가 같으면 두 번째 수가 작은 것이, 두 번째 수도 같으면 세 번째 수가 작은 것이….

N이 주어지면, 아래의 두 소문제 중에 하나를 풀어야 한다. k가 주어지면 k번째 순열을 구하고, 임의의 순열이 주어지면 이 순열이 몇 번째 순열인지를 출력하는 프로그램을 작성하시오.

입력:

첫째 줄에 N(1≤N≤20)이 주어진다. 둘째 줄의 첫 번째 수는 소문제 번호이다. 1인 경우 k(1≤k≤N!)를 입력받고, 2인 경우 임의의 순열을 나타내는 N개의 수를 입력받는다. N개의 수에는 1부터 N까지의 정수가 한 번씩만 나타난다.

출력:

k번째 수열을 나타내는 N개의 수를 출력하거나, 몇 번째 수열인지를 출력하면 된다.

풀이방법:

 한 문제에 K번째 수열을 구하는 문제와 주어진 수열이 몇 번째인지 구하는 문제가 합쳐져 있다. 두 소문제는 주어진 수 중 맨 앞의 숫자로 구별되며, 이를 command(c)로 구분해 각 소문제를 풀도록 한다.

 첫 번째 소문제는 K번째 수열을 구하는 문제다. 앞의 자릿수부터 계산하며, 주어진 수 K로부터 만들 수 있는 경우의 수를 빼주며 한자리씩 정해나간다. 즉, 예제의 경우 3번째 수열을 구하는 문제에서 맨 앞자리를 a인 경우의 수는 3!개이다. 따라서 3번째 수열은 0~3!번째 수열에 속할 것이므로, 맨 앞자리는 1인 것을 알 수 있다. 이러한 방법을 계속하여 k번째 수열을 찾는다.

 두 번째 소문제는 첫 번째 소문제의 역으로 구할 수 있다. 팩토리얼을 사용해 k번째 수열을 구했던 것의 역으로 팩토리얼을 더하면서 k를 찾도록 한다.

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
= int(input())
tmp = list(map(int,input().split()))
c, numbers = tmp[0],tmp[1:]
factorial = [0]*21
factorial[0= 1
for i in range(1,21):
    factorial[i] = factorial[i-1]*i
if c==1:
    answer = []
    numbers = numbers[0]
    used = [0]*(N+1)
    for i in range(N):
        for j in range(1,N+1):
            if used[j]==1:
                continue
            if factorial[N-i-1]<numbers:
                numbers-=factorial[N-i-1]
            else:
                used[j]=1
                answer.append(j)
                break
    print(*answer)
elif c==2:
    answer = 0
    used = [0]*(N+1)
    for i in range(N):
        for j in range(1,numbers[i]):
            if used[j] == 0:
                answer += factorial[N-1-i]
        used[numbers[i]] = 1
    print(answer+1)
cs

문제링크:

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

 

1722번: 순열의 순서

첫째 줄에 N(1≤N≤20)이 주어진다. 둘째 줄의 첫 번째 수는 소문제 번호이다. 1인 경우 k(1≤k≤N!)를 입력받고, 2인 경우 임의의 순열을 나타내는 N개의 수를 입력받는다. N개의 수에는 1부터 N까지

www.acmicpc.net

 

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

[BOJ]6593. 상범 빌딩  (0) 2021.09.29
[BOJ]12904. A와 B  (0) 2021.09.28
[BOJ]1351. 무한 수열  (0) 2021.09.24
[BOJ]1202. 보석 도둑  (0) 2021.09.23
[BOJ]1057. 토너먼트  (0) 2021.09.16

+ Recent posts