2024. 8. 10. 21:32ㆍ파이썬(Python)
1. dx, dy를 이용하기
- 어떤 특정한 위치에서 숫자에 따라 한 칸 이동한다.
- 0은 위쪽, 1은 오른쪽, 2는 아래쪽, 3은 왼쪽이다.
num = int(input('숫자를 입력하세요: '))
pos_x, pos_y = 0, 0
if num == 0:
pos_y += 1
elif num == 1:
pos_x += 1
elif num == 2:
pos_y -= 1
else:
pos_x -= 1
print(f'이동한 후 위치는 {pos_x}, {pos_y}이다.')
숫자를 입력하세요: 0
이동한 후 위치는 0, 1이다.
숫자를 입력하세요: 1
이동한 후 위치는 1, 0이다.
숫자를 입력하세요: 2
이동한 후 위치는 0, -1이다.
숫자를 입력하세요: 3
이동한 후 위치는 -1, 0이다.
- 위 코드에서 비슷한 조건문이 반복되는 것을 알 수 있다.
- 특정 방향으로 이동하는 경우 좌, 우를 움직이는 dx, 상, 하를 움직이는 dy를 각각 리스트로 정의하여 사용할 수 있다.
- dx, dy 리스트를 정의하면 코드는 다음과 같다.
num = int(input('숫자를 입력하세요: '))
pos_x, pos_y = 0, 0
dx, dy = [0, 1, 0, -1], [1, 0, -1, 0]
pos_x, pos_y = pos_x+dx[num], pos_y+dy[num]
print(f'이동한 후 위치는 {pos_x}, {pos_y}이다.')
숫자를 입력하세요: 0
이동한 후 위치는 0, 1이다.
숫자를 입력하세요: 1
이동한 후 위치는 1, 0이다.
숫자를 입력하세요: 2
이동한 후 위치는 0, -1이다.
숫자를 입력하세요: 3
이동한 후 위치는 -1, 0이다.
Q) 방향에 따른 이동
- 이동 명령의 개수 n과 초기 위치 x, y를 입력한다.
- n번의 이동 방향과 이동 거리를 입력한다.
- 방향은 N, E, S, W이고 각각 위, 오른, 아래, 왼쪽을 의미한다.
- 예를 들어, N 3이면 위쪽으로 3칸 움직인다는 의미이다.
- n번의 이동 끝에 최종 위치를 출력하라.
n = int(input())
x, y = map(int, input().split())
dx, dy = [0, 1, 0, -1], [1, 0, -1, 0]
directions = {'N': 0, 'E': 1, 'S': 2, 'W': 3}
for _ in range(n):
d, distance = input().split()
distance = int(distance)
x, y = x+dx[directions[d]]*distance, y+dy[directions[d]]*distance
print(x, y)
>> 5
>> 2 3
>> N 4
>> S 2
>> E 6
>> W 3
>> S 1
5 4
- x축 방향(좌, 우)의 변화량 dx, y축 방향(위, 아래)의 변화량 dy를 리스트로 나타낸다.
- 딕셔너리를 사용해 이동 방향을 나타내는 문자에 대응하는 숫자를 저장한다.
- 이동 방향에 따른 숫자가 dx, dy의 index가 되고, 방향을 결정하여 distance만큼 이동한다.
2. 방향 회전
- 예를 들어 dx, dy를 시계 방향으로 적으면 다음과 같다.
dx, dy = [0, 1, 0, -1], [1, 0, -1, 0]
d_num = 0
x, y = 0, 0
print(f'{x+dx[d_num]}, {y+dy[d_num]}')
d_num += 1
print(f'{x+dx[d_num]}, {y+dy[d_num]}')
d_num += 1
print(f'{x+dx[d_num]}, {y+dy[d_num]}')
d_num += 1
print(f'{x+dx[d_num]}, {y+dy[d_num]}')
0, 1
1, 0
0, -1
-1, 0
- 위치를 (0, 0)이라고 할 때, d_num이 증가하면서 각각 위쪽, 오른쪽, 아래쪽, 왼쪽 방향으로 이동할 수 있다.
- 즉, dx, dy에 방향 값을 시계 방향 순서로 정의하고 d_num을 증가하면 시계 방향으로 90도 회전을 할 수 있다.
- d_num이 3 (왼쪽) 일 때 4가 되면 index error가 발생하므로 0 (위쪽)이 돼야 한다.
- 따라서 시계 방향으로 90도 회전한 이후의 방향은 (d_num+1)%4이다.
- 만약 반시계 방향은 d_num에서 1을 빼주면 된다.
- 이때, d_num이 0 (위쪽) 일 때 반시계 방향으로 하면 3 (왼쪽)이 되어야 한다.
- 따라서 반시계 방향으로 90도 회전한 이후의 방향은 (d_num-1+4)%4이다.
Q) 방향에 따른 이동
- 초기 위치 (x, y)를 입력하고 방향 (N, E, S, W)을 입력한다.
- N, E, S, W은 각각 위쪽, 오른쪽, 아래쪽, 왼쪽을 의미한다.
- 명령을 문자열 형태로 입력한다.
- 명령은 L, R, F 중 하나이고 각각 반시계방향 회전, 시계방향 회전, 앞으로 직진을 의미한다.
- 명령을 수행한 후 최종 위치를 출력하라.
x, y = map(int, input('초기 위치: ').split())
curr_d = input('방향 입력: ')
ds = {'N': 0, 'E': 1, 'S': 2, 'W': 3}
d = ds[curr_d]
dx, dy = [0, 1, 0, -1], [1, 0, -1, 0]
inp_ds = input()
for val in inp_ds:
if val == 'L':
d = (d-1+4) % 4
elif val == 'R':
d = (d+1) % 4
else:
x, y = x+dx[d], y+dy[d]
print(x, y)
>> 초기 위치: 3 6
>> 방향 입력: W
>> FFLLFRRFLF
1 5
- 각 방향을 숫자에 매핑한 딕셔너리를 정의한다. (ds)
- 입력한 방향을 딕셔너리에서 찾아 숫자로 변환하여 d에 저장한다.
- dx, dy를 정의하여 위쪽, 오른쪽, 아래쪽, 왼쪽을 각각 0, 1, 2, 3으로 설정한다.
- 이동 명령인 inp_ds에 따라 L, R, F에 해당하는 명령을 실행한다.
- L은 반시계 방향으로 회전하고, R은 시계 방향으로 회전하여 d를 증가, 감소한다.
- F는 현재 방향으로 1만큼 이동하며, dx dy에 따라 x, y를 수정한다.
3. 격자, 2차원 배열에서 dx, dy 활용
- arr이라는 2차원 배열이 존재한다. arr [x][y]는 x행 y열에 있는 값이다.
- arr [x][y]에서 위쪽 값은 arr [x-1][y]이고 아래쪽 값은 arr [x+1][y]이다.
- 오른쪽 값은 arr [x][y+1]이고, 왼쪽 값은 arr [x][y-1]이다.
- 따라서, 위쪽, 오른쪽, 아래쪽, 왼쪽을 정의하는 dx, dy는 다음과 같다.
dx, dy = [-1, 0, 1, 0], [0, 1, 0, -1]
3-1. in_range 함수 설정
- 만약, (3, 3) 크기의 격자가 있다고 하자.
0 0 0
1 1 1
2 2 2
- 만약 3행 1열에 있는 2의 상, 하, 좌, 우의 값들을 알고 싶다.
- 하지만 아래쪽 방향에 있는 위치는 4행 1 열이고, 리스트의 index error가 발생한다.
- 왼쪽 방향에 있는 위치는 3행 0 열이고, 이중 리스트에서 2번째의 -1번째 index이므로 구하고자 하는 값이 아니다.
- 문제를 해결하기 위해 구하고자 하는 방향의 위치가 격자 내에 있는 위치인지 확인하는 함수를 설정한다.
def in_range(x, y):
return x >= 0 and x < m and y >= 0 and y < n # m은 행, n은 열
- 크기가 m행 n열이라고 하면 (x, y)가 격자 안에 들어오면 True, 격자를 벗어나면 False를 반환한다.
- in_range 함수를 확인하여 격자 범위 안에 들어오는지 확인해야 한다.
Q) 인접한 1의 개수
- n을 입력하여 n행 n열의 격자를 만든다.
- 격자는 0과 1만 존재한다.
- 각 칸에서 상, 하, 좌, 우를 선택하여 1의 개수가 1개~4개의 개수를 세어 출력하라.
def in_range(x, y):
return x >= 0 and x < n and y >= 0 and y < n
n = int(input())
arr = [list(map(int, input().split())) for _ in range(n)]
dxs, dys = [-1, 0, 1, 0], [0, 1, 0, -1]
cnts = [0, 0, 0, 0, 0]
for x in range(n):
for y in range(n):
cnt = 0
for dx, dy in zip(dxs, dys):
nx, ny = x+dx, y+dy
if in_range(nx, ny) and arr[nx][ny] == 1:
cnt += 1
cnts[cnt] += 1
for idx in range(1, 5):
print(f'인접한 1이 {idx}개인 위치는 {cnts[idx]}')
>> 4
>> 0 1 0 1
>> 1 0 1 0
>> 1 1 0 1
>> 0 1 1 0
인접한 1이 1개인 위치는 2
인접한 1이 2개인 위치는 6
인접한 1이 3개인 위치는 2
인접한 1이 4개인 위치는 2
- 그림에서 보면 노란색 칸을 기준으로 상, 하, 좌, 우에 1이 있는 개수를 의미한다.
- 각각 x, y의 변화량을 나타내는 리스트를 정의한다. (dxs, dys)
- 칸 주변에 1의 개수에 대한 리스트를 정의한다. (cnts)
- cnts [idx]는 주변에 있는 1의 개수가 idx만큼 있는 칸의 개수를 의미한다.
- zip을 사용해서 dxs, dys의 값을 순서대로 각각 하나씩 뽑아 방향을 설정한다.
- in_range 함수를 설정해 격자 범위 내에 있는지 확인한다.
- 주변 위치로 이동한 좌표를 nx, ny에 넣어 in_range가 True이고 해당 값이 1이면 cnt를 1 증가한다.
- cnts의 index가 cnt인 값을 1 증가시킨다.
- 해당 개수에 대한 위치에 있는 1의 개수를 출력한다.
Q) 땅따먹기 게임
- n, m을 입력하고 m개의 x, y를 입력한다.
- n * n 격자 내에 m번의 x, y 위치에 돌을 놓는다.
- 이때, 돌을 놓은 땅을 기점으로 인접한 4개의 칸 모두 돌이 있다면 그 땅을 점령한다.
- 점령한 땅의 개수를 구하라.
def in_range(x, y):
return 0 <= x < n and 0 <=y < n
n,m = map(int, input().split())
arr = [[0] * n for _ in range(n)]
dxs, dys = [-1, 0, 1, 0], [0, 1, 0, -1]
sum_cnt = 0
for _ in range(m):
r, c = map(int, input().split())
arr[r-1][c-1] = 1
cnt = sum(1 for dx, dy in zip(dxs, dys) if in_range(r-1+dx, c-1+dy) and arr[r-1+dx][c-1+dy] == 1)
if cnt == 4:
sum_cnt += 1
print(f'점령한 땅의 개수는 {sum_cnt}')
>> 4 8
>> 1 2
>> 2 1
>> 2 3
>> 3 2
>> 2 2
>> 4 3
>> 3 4
>> 3 3
점령한 땅의 개수는 2
- n*n의 0이 원소인 배열 arr을 생성한다.
- x, y에 돌을 놓은 위치라고 표시하기 위해 arr [x-1][y-1]에 1이라 표시한다. (리스트에 저장하기 위해 각 위치에 1을 뺀 x-1, y-1에 값을 저장한다.)
- 현재 위치인 x, y를 기점으로 상하좌우에 1인 값을 확인한다. (dxs, dys 사용)
- 또한 in_range를 통해 상하좌우를 탐색하는 위치가 격자 내부에 있는지 확인한다.
- 네 방향 모두 1이면 x, y의 땅을 점령할 수 있으므로 점령한 땅의 개수 sum_cnt를 1 증가하여 답을 출력한다.
Q) 이동하며 숫자 계산
- n, m을 입력하여 n*n 격자의 정보를 주어지고 m개의 명령을 입력한다.
- x, y를 입력하여 첫 시작의 좌표를 입력한다. (x, y는 n 이하)
- 명령은 R, L, F 중 하나이다.
- R은 현재 방향에서 시계 방향으로 회전. L은 현재 방향에서 반시계 방향으로 회전한다.
- F는 현재 방향으로 한 칸 전진하며 숫자를 더하거나 뺀다.
- 첫 시작 방향은 위쪽이고 첫 번째 전진하게 되면 기존 위치의 숫자와 전진한 후 위치의 숫자를 더한다.
- F로 숫자를 더했다면 이후에 F가 나올 때에는 숫자를 뺀다.
- 마찬가지로 F로 숫자를 뺐다면 이후에 F가 나오면 숫자를 더한다.
- 이때 모든 숫자를 더하거나 뺀 값의 결과를 출력하라.
>> 3 8 # n, m
>> 2 2 # x, y
>> RFFFLFLF
>> 1 2 3
>> 4 5 6
>> 7 8 9
10
- 노란색은 더하고 초록색은 뺀다.
- 따라서 5+6-3+2 = 10이다.
def in_range(x,y):
return 0<=x<n and 0<=y<n
n, m = map(int,input().split())
x, y = map(int,input().split())
commands = input()
arr = [list(map(int, input().split())) for _ in range(n)]
dxs, dys = [-1, 0, 1, 0], [0, 1, 0, -1]
i=0
ans = arr[x-1][y-1]
x, y = x-1, y-1
isplus = True
for c in commands:
if c == 'R':
i=(i+1)%4
elif c == 'L':
i=(i+3)%4
else:
nx, ny = x+dxs[i], y+dys[i]
if in_range(nx, ny):
if isplus:
ans += arr[nx][ny]
isplus = False
else:
ans -= arr[nx][ny]
isplus = True
x, y = nx, ny
print(ans)
- dxs, dys를 사용해 위, 오른, 아래, 왼쪽을 나타내는 방향벡터를 설정한다.
- i는 현재 방향의 인덱스를 나타낸다.
- ans는 결괏값을 나타내고 초기값은 현재 (x, y)의 값을 나타내기 위해 x-1, y-1 인덱스의 arr 값을 저장한다.
- 리스트의 인덱스로 만들기 위해 x, y를 각각 1을 뺀다.
- isplus는 현재 더할지 뺄지 결정하는 변수이다. True이면 더하고 False이면 뺀다.
- 명령이 R이면 인덱스를 1 증가시켜 오른쪽으로 회전한다.
- 명령이 L이면 인덱스를 3 증가시켜 왼쪽으로 회전한다.
- 4로 나눈 나머지 연산으로 각각의 회전을 구현한다.
- F를 하면 현재 방향으로 이동한다.
- 이동 후 위치가 범위 내에 있는지 확인하고 범위 내에 있으면 값을 더하거나 뺀다.
- 더한 후에는 False로 설정하여 다음 작업에 빼기 연산으로 설정한다.
- 뺀 후에는 True로 설정하여 다음 작업에 더하기 연산으로 설정한다.
- 명령이 끝난 후에는 결괏값을 출력한다.
'파이썬(Python)' 카테고리의 다른 글
[Python] dx dy 조건에 따른 방향 변환. 문자가 주어진 경우. 숫자 채우기 (0) | 2024.11.06 |
---|---|
[Python] 파이썬으로 스도쿠 문제 풀기 (0) | 2024.06.09 |
[Python] 배열에 기록하여 문제 풀기 (0) | 2023.12.18 |
[Python] 최장 연속 부분 수열 (0) | 2023.11.11 |
[Python] 사각형 넓이 문제 - 이중 배열 이용. 겹치는 영역. 겹치지 않는 영역. 최소 사각형 넓이 (0) | 2023.11.04 |