1
2
3
4
5
6
7
import sys, random
sys.path.append("/home/swyoo/algorithm/")
from utils.verbose import logging_time
from utils.generator import random2D
from sys import stdin
from copy import deepcopy
import numpy as np
14891. 톱니바퀴
Beakjoon의 문제.
톱니바퀴를 돌리는 문제, 톱니 바퀴는 4
개이며 각 바퀴의 톱니는 8
개씩 있다.
saws
의 각 톱니바퀴는 시계방향(clock-wise)와 반시계방향(counter-clock-wise)로 돌릴 수 있으며
moves
로 돌릴 톱니바퀴의 index와 방향(direction) 이 주어진다.
주의사항은 문제에서 주어진 톱니바퀴의 index는 번째 수 이므로 -1
을 하여 전처리한다.
돌리는 방향은 1
은 시계방향(clock-wise), -1
은 반시계방향(counter-clock-wise)이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
plot = lambda a: print(np.array(a))
stdin = open('data/saws.txt')
input = stdin.readline
saws = [list(map(int, input().strip())) for _ in range(4)]
k = int(input())
moves = [list(map(int, input().split())) for _ in range(k)]
moves = list(map(lambda x: (x[0] - 1, x[1]), moves))
direct = [(7, 0, 1, 2, 3, 4, 5, 6), # clock-wise (->)
(1, 2, 3, 4, 5, 6, 7, 0)] # counter-clock-wise (<-)
left, right, up = 6, 2, 0
plot(saws)
print(moves)
1
2
3
4
5
6
[[1 0 1 0 1 1 1 1]
[0 1 1 1 1 1 0 1]
[1 1 0 0 1 1 1 0]
[0 0 0 0 0 0 1 0]]
[(2, -1), (0, 1)]
Idea
각 톱니바퀴를 주어진 명령에 따라 회전시킬 수 있도록 한다.
톱니바퀴의 adjacent list를 Hard Coding하고, dfs를 통해 연속적으로 움직이도록 한다.
이때 주의해야할 점은 톱니바퀴의 왼쪽(index=6)과 오른쪽(right, index=2)의 극성 S극(1) N극(0)을 보고
회전 방향이 결정된다.
Step1. Rotate a Saw
0번째 톱니 saws[0]
을 회전시켜 보았다.
kind = 1
: clock-wisekind = -1
: counter-clock-wise
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def rotate(a, kind):
idx = 0 if kind == 1 else 1
return [a[direct[idx][x]] for x in range(8)]
def saw2plot(saw):
a = [[-1] * 3 for _ in range(3)]
a[0][1], a[0][2], a[1][2], a[2][2], a[2][1], a[2][0], a[1][0], a[0][0] = saw
plot(a)
print(saws[0], 'is as follows. ')
saw2plot(saws[0])
print("rotate according to clock-wise as follows.")
saw2plot(rotate(saws[0], 1)) # -> 방향 회전
print("rotate according to counter-clock-wise as follows.")
saw2plot(rotate(saws[0], -1)) # <- 방향 회전
1
2
3
4
5
6
7
8
9
10
11
12
13
[1, 0, 1, 0, 1, 1, 1, 1] is as follows.
[[ 1 1 0]
[ 1 -1 1]
[ 1 1 0]]
rotate according to clock-wise as follows.
[[ 1 1 1]
[ 1 -1 0]
[ 1 0 1]]
rotate according to counter-clock-wise as follows.
[[ 1 0 1]
[ 1 -1 0]
[ 1 1 1]]
Step2. DFS
DFS를 통해 연속된 회전 구현.
주의사항
1. adjacent list
구현시, 톱니의 idex이외에도 오른쪽에서 온건지 왼쪽에서 온건지 notification필요.
2. 돌리기 전에 L, R
의 상태를 저장해 놓아야 한다. 이유는 다음과 같다.
2 - 1. adjacent한 톱니 saws[j]
를 돌릴지 말지의 여부
2 - 2. L != saws[j][right]
또는 R != saws[j][left]
이면 saws[i]
의 회전방향 kind
와 반대로 돌린다.
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
@logging_time
def solution(saws, moves, show=False):
adj = {0: [(1, right)],
1: [(0, left), (2, right)],
2: [(1, left), (3, right)],
3: [(2, left)]}
def dfs(i, kind, seen):
seen.add(i)
L, R = saws[i][left], saws[i][right]
saws[i] = rotate(saws[i], kind)
for j, opp in adj[i]:
if j not in seen:
if opp == left and L != saws[j][right]:
dfs(j, -kind, seen)
elif opp == right and R != saws[j][left]:
dfs(j, -kind, seen)
for sidx, kind in moves:
dfs(sidx, kind, set())
if show:
print("move a saw [{}] according to the direction [{}]".format(sidx, kind))
for k, saw in enumerate(saws):
print('saw[{}] is as follows.'.format(k)), saw2plot(saw)
ans = 0
for i in range(4):
if saws[i][up]:
ans += 2 ** i
return ans
print("ans:", solution(saws, moves, show=True, verbose=True))
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
move a saw [2] according to the direction [-1]
saw[0] is as follows.
[[ 1 1 0]
[ 1 -1 1]
[ 1 1 0]]
saw[1] is as follows.
[[ 1 0 1]
[ 0 -1 1]
[ 1 1 1]]
saw[2] is as follows.
[[ 1 1 0]
[ 0 -1 0]
[ 1 1 1]]
saw[3] is as follows.
[[ 1 0 0]
[ 0 -1 0]
[ 0 0 0]]
move a saw [0] according to the direction [1]
saw[0] is as follows.
[[ 1 1 1]
[ 1 -1 0]
[ 1 0 1]]
saw[1] is as follows.
[[ 0 1 1]
[ 1 -1 1]
[ 0 1 1]]
saw[2] is as follows.
[[ 0 1 1]
[ 1 -1 0]
[ 1 1 0]]
saw[3] is as follows.
[[ 1 0 0]
[ 0 -1 0]
[ 0 0 0]]
WorkingTime[solution]: 1.74212 ms
ans: 7
Time Complexity
moves
size를 $n$ 이라 하였을때,
- Rotate: $O(1)$
- A
dfs(i)
call: at most 4 time visit, so $O(1)$
Therefore, $O(n)$
Test Cases
Generate test datasets and get the ans
.
1
2
3
4
5
6
7
size = 1000000
saws = random2D(shape=(4,8), randrange=(0, 1))
moves = [(random.choice(range(4)), random.choice([1, -1])) for _ in range(size)]
plot(saws)
plot(moves)
print("ans:", solution(saws, moves, verbose=True))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
[[0 0 1 0 0 1 0 0]
[1 1 1 0 0 1 0 1]
[0 0 0 0 1 0 1 1]
[0 1 0 1 0 0 1 0]]
[[ 1 1]
[ 2 1]
[ 2 -1]
...
[ 2 1]
[ 0 1]
[ 0 1]]
WorkingTime[solution]: 4199.79739 ms
ans: 2
Submitted Code
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
from sys import stdin
from copy import deepcopy
stdin = open('data/saws.txt')
input = stdin.readline
saws = [list(map(int, input().strip())) for _ in range(4)]
k = int(input())
moves = [list(map(int, input().split())) for _ in range(k)]
moves = list(map(lambda x: (x[0] - 1, x[1]), moves))
direct = [(7, 0, 1, 2, 3, 4, 5, 6), # clock-wise
(1, 2, 3, 4, 5, 6, 7, 0)] # counter-clock-wise
def rotate(a, kind):
idx = 0 if kind == 1 else 1
return [a[direct[idx][x]] for x in range(8)]
left, right, up = 6, 2, 0
def solution(saws, moves):
adj = {0: [(1, right)],
1: [(0, left), (2, right)],
2: [(1, left), (3, right)],
3: [(2, left)]}
def dfs(i, kind, seen):
seen.add(i)
L, R = saws[i][left], saws[i][right]
saws[i] = rotate(saws[i], kind)
for j, opp in adj[i]:
if j not in seen:
if opp == left and L != saws[j][right]:
dfs(j, -kind, seen)
elif opp == right and R != saws[j][left]:
dfs(j, -kind, seen)
for sidx, kind in moves:
dfs(sidx, kind, set())
ans = 0
for i in range(4):
if saws[i][up]:
ans += 2 ** i
return ans
print(solution(saws, moves))
1
2
7
Leave a comment