14499번: 주사위 굴리기

첫째 줄에 지도의 세로 크기 N, 가로 크기 M (1 ≤ N, M ≤ 20), 주사위를 놓은 곳의 좌표 x, y(0 ≤ x ≤ N-1, 0 ≤ y ≤ M-1), 그리고 명령의 개수 K (1 ≤ K ≤ 1,000)가 주어진다. 둘째 줄부터 N개의 줄에 지

www.acmicpc.net

[그림1] 문제의 전개도와 상관없이 가운데 정육각형을 기준으로 한다.

주사위의 윗부분을 0, 옆면은 왼쪽부터 앞쪽 방향으로 1, 2, 3, 4, 바닥 부분을  5로 둔다. 주사위를 주어진 방향에 따라 굴렸을 경우 위 그림에 맞게 면을 수정해준다.

N, M, x, y, K = map(int, input().split())
board = [list(map(int, input().split())) for _ in range(N)]
move = list(map(int, input().split()))

mv = [[0, 0], [0, 1], [0, -1], [-1, 0], [1, 0]] # x, y # move: 1~4
dice = [0, 0, 0, 0, 0, 0] # 위, 왼, 앞, 오른, 뒤, 아래


def roll(d): # 주사위를 굴린다. 위 그림 참고
    global dice
    d0, d1, d2, d3, d4, d5 = dice
    if d == 1: # 동
        dice = [d1, d5, d2, d0, d4, d3]
    elif d == 2: # 서
        dice = [d3, d0, d2, d5, d4, d1]
    elif d == 3: # 북
        dice = [d2, d1, d5, d3, d0, d4]
    elif d == 4: # 남
        dice = [d4, d1, d0, d3, d5, d2]
    else:
        raise ValueError
    return dice


if board[x][y] != 0: # 주사위가 있는 위치의 지도 값이 0 이 아니라면
    dice[-1] = board[x][y] # 주사위의 가장 마지막 원소가 바닥 면의 숫자이다.
    board[x][y] = 0 # 주사위에 복사 후 지도는 0으로 수정

for d in move:
    nx, ny = x + mv[d][0], y + mv[d][1] 
    if 0 <= nx < N and 0 <= ny < M: # 다음 위치로 이동 가능하다면
        dice = roll(d) # 주사위를 굴리고
        if board[nx][ny] == 0: # 지도가 0이라면
            board[nx][ny] = dice[-1] # 주사위 바닥 면의 숫자 복사
        else: # 0이 아니라면
            dice[-1] = board[nx][ny] # 주사위 밑면에 지도의 수 복사
            board[nx][ny] = 0 # 지도는 0으로
        print(dice[0]) # 윗면 출력
        x, y = nx, ny # 다음 위치로 이동
 

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

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

www.acmicpc.net

시간 초과때문에 마지막 새로 생긴 구름의 위치를 생길 수 있는 위치와 사라진 구름의 위치를 반복문 밖으로 빼내 집합으로 구했다.

# 21610 / 마법사 상어와 비바라기
N, M = map(int, input().split())
A = [list(map(int, input().split())) for _ in range(N)]
move = [list(map(int, input().split())) for _ in range(M)]

direction = [ 
    [0, -1], # r, c
    [-1, -1],
    [-1, 0],
    [-1, 1],
    [0, 1],
    [1, 1],
    [1, 0],
    [1, -1],
]
water_copy_dir = [[-1, -1], [-1, 1], [1, -1], [1, 1]]

cloud = [[N-1, 0], [N-1, 1], [N-2, 0], [N-2, 1]]
water_add = [[0 for _ in range(N)] for _ in range(N)]

for d, s in move:
    # 1. 구름 이동
    dd = direction[d-1]
    cloud_moved = []
    for cloud_r, cloud_c in cloud:
        cloud_r = (cloud_r + dd[0] * s) % N
        cloud_c = (cloud_c + dd[1] * s) % N
        # 2. 구름이 있는 곳에 비내림
        A[cloud_r][cloud_c] += 1
        # 물이 증가한 칸 저장
        cloud_moved.append([cloud_r, cloud_c])
    # 4. 증가한 칸 대각선에 물 확인
    for cloud_r, cloud_c in cloud_moved:
        count = 0
        for i in range(4): # 대각에 물이 있는 만큼
            ncr = cloud_r + water_copy_dir[i][0]
            ncc = cloud_c + water_copy_dir[i][1]
            if (0 <= ncr < N and 0 <= ncc < N
                and A[ncr][ncc] > 0):
                count += 1
        A[cloud_r][cloud_c] += count # 물 증가
    # 3. 구름 사라짐
    cloud = []
    for r in range(N):
        for c in range(N):
            if A[r][c] >= 2 and [r, c]:
                cloud.append([r, c])
    # 생성 가능하지만 3.에서 구름이 사라진 위치에는 생성되면 안된다.
    cloud = list(set(map(tuple, cloud)).difference(map(tuple, cloud_moved)))
    for r, c in cloud:
        A[r][c] -= 2
    
print(sum(map(sum, A)))
 

21608번: 상어 초등학교

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

www.acmicpc.net

주어진 순서에 맞게 자리를 정해주는데, 좋아하는 학생이 인접한 칸이 동시에 비어있는 칸 일 수 없다. 인접한 칸은 최대 4칸이고 좋아하는 학생이 있는 경우가 가장 우선이기 때문에 자리 지정의 선호도를 하나의 행렬로 표현할 수 있다. 인접한 칸이 비어있는 경우는 1, 좋아하는 학생이 있는 경우는 10씩 선호도를 추가했다. 이후 선호도가 가장 높은 위의 왼쪽 위치로 자리를 지정해주면 된다.

# 21608 / 상어 초등학교
N = int(input())
students = [list(map(int, input().split())) for _ in range(N**2)]

students_dict = {s[0]: s[1:] for s in students}
classroom = [[0 for _ in range(N)] for _ in range(N)]
adj = [[-1, 0], [0, -1], [0, 1], [1, 0]] # r, c

# 자리 지정
for student in students:
    prefer = [[0 for _ in range(N)] for _ in range(N)] 자리 선정을 위해 선호도 저장
    max_prefer = 0
    max_prefers = [] # 같은 선호도가 나타날 경우 가장 위의 행, 왼쪽 열을 고르기 위해 저장

    for r in range(N):
        for c in range(N):
            if classroom[r][c] != 0: # 자리가 비어있지 않다면 통과
                continue
            p = 0
            for i in range(4): # 현재 위치에서 인접한 칸 중에
                nr = r + adj[i][0]
                nc = c + adj[i][1]
                if 0 <= nr < N and 0 <= nc < N:
                    if classroom[nr][nc] in student[1:]: # 좋아하는 사람이 있다면 
                        p += 10 # 높은 선호도 추가
                    elif classroom[nr][nc] == 0: # 비어있다먄
                        p += 1 # 낮은 선호도 추가
            prefer[r][c] = p # 현재 학생의 이 위치에 대한 선호도 저장

            if max_prefer <= p:
                if max_prefer == p: # 최대 선호도와 같다면 
                    max_prefers.append([r, c]) # 선호하는 자리에 추가
                else:
                    max_prefer = p # 최대 선호도보다 높다면
                    max_prefers = [[r, c]] # 새로운 자리로 수정

    r_, c_ = sorted(max_prefers, key=lambda x: [x[0], x[1]])[0] # 가장 선호하는 자리 중
    classroom[r_][c_] = student[0] # 가장 위, 왼쪽 위치 저장

# 점수 계산
score = 0
for r in range(N):
    for c in range(N):
        count = 0
        for i in range(4):
            nr = r + adj[i][0]
            nc = c + adj[i][1]
            if 0 <= nr < N and 0 <= nc < N: # 주변 학생 중에 좋아하는 사람이 있다면
                if classroom[nr][nc] in students_dict[classroom[r][c]]:
                    count += 1 # 수를 세고
        if count == 0: # 없으면 통과
            continue
        else: # 있으면 해당 점수만큼 추가
            score += 10**(count-1)

print(score)
 

17140번: 이차원 배열과 연산

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

www.acmicpc.net

Counter로 숫자의 빈도를 구하고 정렬해 배열의 행을 바꿔준다. C 연산은 배열을 전치시키고 R 연산을 하는 것과 같으므로 R 연산 하나만 구현하면 된다.

from collections import Counter

def calc(A):
    for i in range(len(A)):
        counts = Counter(A[i]) # 숫자의 개수를 센다
        del counts[0] # 0은 포함시키지 않으므로 제거
        counts = counts.items()
        # i번째 리스트 정렬 (숫자 빈도, 수 크기)
        A[i] = list(sum(sorted(counts, key=lambda x: [x[1], x[0]]), ()))
        if len(A[i]) > 100: # 길이가 100 넘는 경우는 앞에 100개만 사용
            A[i] = A[i][:101]

    max_len = max(list(map(len, A))) # 최대 길이를 기준으로
    for i in range(len(A)): # 짧은 행은 0 추가
        A[i] = A[i] + [0 for _ in range(max_len-len(A[i]))]
    
    return A


r, c, k = map(int, input().split())
A = [list(map(int, input().split())) for _ in range(3)]

t = 0
while t <= 100: # 100초 이후에도 맞지 않다면 -1 출력
    if (r-1 >= len(A) or c-1 >= len(A[r-1]) # 배열의 크기보다 큰 범위를 찾거나
        or A[r-1][c-1] != k): # k가 아닐 경우에는 R 또는 C 연산 실행
        t += 1
        max_len = max(list(map(len, A))) 
        if len(A) >= max_len: # 행이 열보다 길거나 같을 경우
            A = calc(A) # R 연산 수행

        else: # 열이 행보다 길 경우
            A = list(map(list, zip(*A))) # 이차원 배열 전치
            A = calc(A) # R 연산 수행
            A = list(map(list, zip(*A))) # 이차원 배열 전치

    else: # k가 나왔다면 시간 출력
        print(t)
        break
else:
    print(-1)
 

15685번: 드래곤 커브

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

www.acmicpc.net

어떻게 해야 추가되는 좌표가 순서대로 되는지 확인하면서 작성해야된다.

N = int(input())
curves = [list(map(int, input().split())) for _ in range(N)]

direction = [[1, 0], [0, -1], [-1, 0], [0, 1]]

def rotation(x, y, x_o, y_o):
    rotate_m90 = [[0, -1], # 반시계 방향 90도 회전
                 [1, 0]]
    x_ = x - x_o # 원점 이동
    y_ = y - y_o
    x_t = x_*rotate_m90[0][0] + y_*rotate_m90[0][1] # 회전
    y_t = x_*rotate_m90[1][0] + y_*rotate_m90[1][1]
    x_r = x_t + x_o # 원점 복원
    y_r = y_t + y_o
    return x_r, y_r

def dragon_curve(x, y, d, g):
    c = [[x, y], [x+direction[d][0], y+direction[d][1]]] # 0 세대
    curr = 0
    while curr < g:
        c_ = []
        x_o, y_o = c[-1] # 끝점이 회전의 기준점이 된다
        for x, y in c[:-1][::-1]: # 가까운 점부터 회전시켜야 멀리있는 점이 끝점이 된다
            x_r, y_r = rotation(x, y, x_o, y_o) # 좌표 회전 후
            c_.append([x_r, y_r]) # 리스트에 추가
        c.extend(c_) # 전체 좌표들에 추가
        curr += 1 # 세대 추가
    return c


board = [[False for _ in range(101)] for _ in range(101)]
for x, y, d, g in curves:
    coord = set(map(tuple, dragon_curve(x, y, d, g)))
    for x, y in coord:
        board[y][x] = True # 평면에 좌표 추가

count = 0
for y in range(100):
    for x in range(100):
        if (board[y][x] and board[y][x+1]
            and board[y+1][x] and board[y+1][x+1]):
            count += 1 # 네 점이 모두 참이라면 카운트
            
print(count)
 

15683번: 감시

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

www.acmicpc.net

0, 0, 0

0, 3, 0

0, 0, 0

과 같은 입력을 줘서 모든 CCTV가 정확한 방향을 가르키는지, 회전이 잘 되는지 출력해 봐야 한다.

 

from copy import deepcopy

N, M = map(int, input().split())
office = [list(map(int, input().split())) for _ in range(N)]

cctv = []
for n in range(N):
    for m in range(M):
        if office[n][m] not in [0, 6]:
            cctv.append([n, m, office[n][m]])


rotate_90 = [[0, 1],
             [-1, 0]]

def cctv_n(office, num, n, m, d):
    # 1번 cctv를 사용해서 다른 cctv를 만들어준다.
    def cctv_1(office, n, m, d):
        while (0 <= n < N 
               and 0 <= m < M): # 사무실 내에서
            nn, nm = n + d[0], m + d[1] # 벽이 아닐때까지 이동하며
            if (0 <= nn < N and 0 <= nm < M): # 감시 가능 구간으로 설정
                if office[nn][nm] == 0:
                    office[nn][nm] = "#"
                elif office[nn][nm] == 6:
                    break

            n, m = nn, nm
        return office

    if num == 1: # 1번 cctv는 한 방향만 감시
        return cctv_1(office, n, m, d)

    elif num == 2: # 2번 cctv는 한 직선으로 감시하므로
        office = cctv_1(office, n, m, d)
        for _ in range(2): # 90도 회전을 두 번 적용 후 감시 범위 확인
            d = [d[0]*rotate_90[0][0] + d[1]*rotate_90[0][1],
                 d[0]*rotate_90[1][0] + d[1]*rotate_90[1][1]]
        return cctv_1(office, n, m, d)
    
    else:
        for i in range(num-2): # 나머지는 90도 단위로 회전하므로 
            office = cctv_1(office, n, m, d) # 감시 범위에 따라 회전 후 적용
            d = [d[0]*rotate_90[0][0] + d[1]*rotate_90[0][1],
                 d[0]*rotate_90[1][0] + d[1]*rotate_90[1][1]]
    return cctv_1(office, n, m, d)


direction = [[0, 1], [1, 0], [0, -1], [-1, 0]] # E, S, W, N
min_count = 64
arr = []

def back_tracking(depth):
    global min_count

    if depth == len(cctv):
        count = 0
        office_copy = deepcopy(office)
        # 각 cctv마다 시작 방향 지정
        for (n, m, num), d in zip(cctv, arr):
            office_copy = cctv_n(office_copy, num, n, m, direction[d])
        for row in office_copy:
            count += row.count(0)
        min_count = min(min_count, count)
        return
    
    else:
        for i in range(4):
            arr.append(i)
            back_tracking(depth+1)
            arr.pop()

back_tracking(0)
print(min_count)
 

14891번: 톱니바퀴

첫째 줄에 1번 톱니바퀴의 상태, 둘째 줄에 2번 톱니바퀴의 상태, 셋째 줄에 3번 톱니바퀴의 상태, 넷째 줄에 4번 톱니바퀴의 상태가 주어진다. 상태는 8개의 정수로 이루어져 있고, 12시방향부터

www.acmicpc.net

 

# 현재 기어에서 왼쪽이나 오른쪽 기어 회전 여부
def is_spin(num, d):
    left, right = 0, 0
    if num == 1: # 가장 왼쪽 기어라면
        if gear[num][2] != gear[num+1][-2]: # 오른쪽만 확인
            right = d * -1 # 회전 방향은 반대
        return left, right
        
    elif num == 4: # 가장 오른쪽 기어라면
        if gear[num][-2] != gear[num-1][2]: # 왼쪽만 확인
            left = d * -1
        return left, right
    
    else: # 중간에 있는 기어는 양쪽 모두 확인
        if gear[num][2] != gear[num+1][-2]:
            right = d * -1
        if gear[num][-2] != gear[num-1][2]:
            left = d * -1
        return left, right
    
# 전체 기어 중 회전해야 하는 기어 확인
def spin_gear(num, d):
    global spin
	
    # 처음 회전시키는 기어 양 옆 확인
    left, right = is_spin(num, d)

	# 왼쪽 기어를 회전 시켜야 한다면 
    if left and spin[num-1] == 0:
        spin[num-1] = left # 왼쪽 기어 회전 방향 저장
        spin_gear(num-1, left) # 왼쪽 기어에서 다음 기어 확인

	# 오른쪽 기어를 회전 시켜야 한다면 상동
    if right and spin[num+1] == 0:
        spin[num+1] = right
        spin_gear(num+1, right)


A = list(input()) # 0: N, 1: S
B = list(input())
C = list(input())
D = list(input())

K = int(input()) # 1: clock, -1: counter clock
spins = [list(map(int, input().split())) for _ in range(K)]
gear = {1: A, 2: B, 3: C, 4: D}


for g, d in spins:
    spin = [0 for _ in range(5)]
    
    spin_gear(g, d) # 회전시켜야 하는 기어 확인
    spin[g] = d # 처음 회전 시키는 기어 회전
    for idx, s in enumerate(spin[1:], 1):
        if s == 1: # 시계 방향
            gear[idx] = [gear[idx][-1]] + gear[idx][:-1]
        elif s == -1: # 반시계 방향
            gear[idx] = gear[idx][1:] + [gear[idx][0]]

print(int(''.join(gear[i][0] for i in range(4, 0, -1)), base=2))​

'알고리즘 > 백준' 카테고리의 다른 글

[백준 파이썬] 15685 드래곤 커브  (0) 2023.07.28
[백준 파이썬] 15683 감시  (0) 2023.07.27
[백준 파이썬] 14503 로봇 청소기  (0) 2023.07.21
[백준 파이썬] 4179 불!  (0) 2023.07.20
[백준 파이썬] 14501 퇴사  (0) 2023.07.20
 

14503번: 로봇 청소기

첫째 줄에 방의 크기 $N$과 $M$이 입력된다. $(3 \le N, M \le 50)$  둘째 줄에 처음에 로봇 청소기가 있는 칸의 좌표 $(r, c)$와 처음에 로봇 청소기가 바라보는 방향 $d$가 입력된다. $d$가 $0$인 경우 북쪽

www.acmicpc.net

청소해야 할 칸이 있으면 우선 반시계 방향으로 90도 회전한다. 이 부분만 주의하면 된다.

N, M = map(int, input().split())
r, c, d = map(int, input().split())
room = [list(map(int, input().split())) for _ in range(N)]

direction = [[0, -1], [1, 0], [0, 1], [-1, 0]] # x, y / 문제에서 주어진 대로 북, 동, 남, 서쪽이다.
count = 0

while True:
    # 1. 현재 위치가 청소되어있지 않다면 해준다.
    if room[r][c] == 0:
        count += 1
        room[r][c] = 9

    # 3. 반시계 방향으로 회전하기 위해 현재 방향 인덱스보다 하나 적은 값부터 줄여나간다.
    for i in range(3, -1, -1):
        nr = r + direction[(d+i)%4][1] # 예를들어 현재 방향이 남쪽(2)이라면 
        nc = c + direction[(d+i)%4][0] # 1, 0, 3, 2 순으로 확인한다.

        # 방 범위를 넘어가는 경우는 체크하지 않는다.
        if ((nr < 0 or nr > N-1) or (nc < 0 or nc > M-1)):
            continue
        # 청소를 해야한다면 방향을 청소해야하는 방향으로 틀어주고 그 방향으로 한 칸 이동한다.
        elif room[nr][nc] == 0:
            d = (d+i)%4
            r = nr
            c = nc
            break
    else:
        # 2. 청소할 칸이 없거나 벽이라면 현재 방향의 반대 방향으로 한 칸 이동한다.
        # 바라보는 방향은 유지한다.
        r = r + direction[(d+2)%4][1]
        c = c + direction[(d+2)%4][0]

        # 뒤로 이동한 위치가 방 범위를 넘어가거나 벽이라면 종료한다.
        if ((r < 0 or r > N-1) or (c < 0 or c > M-1)
            or room[r][c] == 1):
            break
print(count)

'알고리즘 > 백준' 카테고리의 다른 글

[백준 파이썬] 15683 감시  (0) 2023.07.27
[백준 파이썬] 14891 톱니바퀴  (0) 2023.07.27
[백준 파이썬] 4179 불!  (0) 2023.07.20
[백준 파이썬] 14501 퇴사  (0) 2023.07.20
[백준 파이썬] 3190 뱀  (0) 2023.07.19

+ Recent posts