새소식

PS/백준

[백준/10875] 뱀 (Python)

  • -

Problem : https://www.acmicpc.net/problem/10875

 

10875번: 뱀

가로 길이와 세로 길이가 모두 2L + 1인 2차원 격자판이 있다. 이 격자판의 각 칸을 그 좌표에 따라 (x, y)로 표현하기로 한다. 격자판의 가운데 칸의 좌표는 (0, 0)이고, 맨 왼쪽 맨 아래 칸의 좌표는

www.acmicpc.net

Difficulty : Platinum 5

Status : Solved

Time : 01:45:29

 


 

문제 설명

 

더보기

가로 길이와 세로 길이가 모두 2L + 1인 2차원 격자판이 있다. 이 격자판의 각 칸을 그 좌표에 따라 (x, y)로 표현하기로 한다. 격자판의 가운데 칸의 좌표는 (0, 0)이고, 맨 왼쪽 맨 아래 칸의 좌표는 (−L, −L), 그리고 맨 오른쪽 맨 위 칸의 좌표는 (L, L)이다. x좌표는 왼쪽에서 오른쪽으로 갈수록, y좌표는 아래에서 위로 갈수록 증가한다.

이 격자판의 (0, 0) 칸에 한 마리의 뱀이 자리를 잡고 있다. 처음에는 뱀의 크기가 격자판의 한 칸의 크기와 같으며, 뱀의 머리는 격자판의 오른쪽을 바라보고 있다. 이 뱀은 자신이 바라보고 있는 방향으로 1초에 한 칸씩 몸을 늘려나가며, 뱀의 머리는 그 방향의 칸으로 옮겨가게 된다. 예를 들어 위의 그림과 같이 L = 3인 경우를 생각해 보자. 뱀은 처음에 (0, 0)에 있으며, 그 크기는 격자판 한 칸 만큼이고, 뱀의 머리가 바라보고 있는 방향은 오른쪽이다. 1초가 지나고 나면 이 뱀은 몸을 한 칸 늘려서 (0, 0)과 (1, 0)의 두 칸을 차지하게 되며, 이때 (1, 0) 칸에 뱀의 머리가 놓이게 된다. 1초가 더 지나고 나면 (0, 0), (1, 0), (2, 0)의 세 칸을 차지하게 되고, 뱀의 머리는 (2, 0)에 놓이게 된다.

이 뱀은 자신의 머리가 향하고 있는 방향을 일정한 규칙에 따라 시계방향, 혹은 반시계방향으로 90도 회전한다. 1번째 회전은 뱀이 출발한지 t1 초 후에 일어나며 i(i > 1)번째 회전은 i − 1번째 회전이 끝난 뒤 ti 초 후에 일어난다. 단, 뱀은 ti 칸 만큼 몸을 늘린 후에 머리를 회전하며 머리를 회전하는 데에는 시간이 소요되지 않는다고 가정한다.

만일 뱀의 머리가 격자판 밖으로 나가게 되면, 혹은 뱀의 머리가 자신의 몸에 부딪히게 되면 이 뱀은 그 즉시 숨을 거두며 뱀은 숨을 거두기 직전까지 몸을 계속 늘려나간다.

뱀이 머리를 회전하는 규칙, 즉 ti 와 그 방향에 대한 정보가 주어졌을 때, 뱀이 출발한지 몇 초 뒤에 숨을 거두는지를 알아내는 프로그램을 작성하라.

 

입력 및 출력

 

더보기

입력

첫 번째 줄에 정수 L(1 ≤ L ≤ 10^8)이 주어진다. 두 번째 줄에는 머리의 방향을 몇 번 회전할 것인지를 나타내는 정수 N(0 ≤ N ≤ 10^3)이 주어진다. 다음 N 개의 줄에 뱀이 머리를 어떻게 회전하는지에 대한 정보가 주어진다. i(1 ≤ i ≤ N)번째 줄에 정수 t_i(1 ≤ t_i ≤ 2 · 10^8)와 dir_i 가 차례로 주어지며 dir_i 는 문자 L, 또는 R 중 하나이다. 뱀은 i = 1인 경우 출발, 그 외의 경우엔 i − 1번째 회전으로부터 t_i 초 후에 dir_i 의 방향으로 머리를 회전하며, 만일 dir_i 가 L 이라면 왼쪽 (반시계방향)으로, R 이라면 오른쪽 (시계방향)으로 90도 회전한다.

 

출력

첫 번째 줄에 답을 나타내는 값을 하나 출력한다. 이 값은 뱀이 출발한지 몇 초 후에 숨을 거두는지를 나타낸다.

 

입력 예시

3
4
2 L
2 L
1 L
5 R

 

출력 예시

7

 

 


 

풀이

교통사고 문제. 구현 문제인데도 불구하고 엄청 오래 해맸던 것 같다.

 

점, 그러니까 좌표를 기준으로 문제를 풀이하면 무조건 시간 초과 및 메모리 초과를 겪게 된다. 최대 크기가 2*10^8이므로.즉 점이 아닌 선을 기준으로 문제를 풀이해보면 된다.

  • 지금까지 저장해 온 선들을 저장하였다고 가정하였을 때,
  • 원래 좌표 (x, y)에서 다음 회전 시간 t_i까지의 이동 좌표 (ax, ay)를 구한다.
  • 새로 생성된 선이 지금까지의 선들과 충돌하는지 여부를 검사한다.
    • 만약 하나 이상이 충돌한다면, 충돌하는 최소 거리를 구한다. 두 선분 이상과 동시에 충돌할 수도 있다는 점을 명심하자.
    • 수직으로 만나거나, 수평으로 만나는 경우로 나뉜다.
  • 만약 충돌하지 않았다면 새로운 선을 다시 저장하고, 총 이동거리를 업데이트한다.
  • 충돌하였다면 충돌 최소 거리를 더한 최종값을 반환한다.

 

import sys
input = sys.stdin.readline

dx = [1, 0, -1, 0]
dy = [0, 1, 0, -1]
L = int(input())
N = int(input())
MAX = L*2+1

next_dir = { 'L' : 1, 'R' : -1, 'S' : 0 }

rotate_list = [input().split() for _ in range(N)]
rotate_list.append((MAX, 'S'))
line_list = [(-L-1, -L-1, L+1, -L-1, 0),
            (-L-1, L+1, L+1, L+1, 0),
            (-L-1, -L-1, -L-1, L+1, 1),
            (L+1, -L-1, L+1, L+1, 1)]

def find_crash(x, y, ax, ay, r) :
  _line_list = line_list if len(line_list) == 4 else line_list[1:]
  result = MAX
  for idx, (sx, sy, ex, ey, dir) in enumerate(_line_list) :
    if r % 2 == dir % 2:
      if x == ax == sx :
        min_y, max_y = min(sy, ey), max(sy, ey)
        if min_y <= ay <= max_y or min(y, ay) <= min_y < max(y, ay):
          dist = min_y - y if y < ay else y - max_y
          result = min(result, dist)
      elif y == ay == sy :
        min_x, max_x = min(sx, ex), max(sx, ex)
        if min_x <= ax <= max_x or min(x, ax) <= min_x <= max(x, ax):
          dist = min_x - x if x < ax else x - max_x
          result = min(result, dist)
    else :
      if sx == ex :
        min_x, max_x = min(x, ax), max(x, ax)
        min_y, max_y = min(sy, ey), max(sy, ey)
        if min_x <= sx <= max_x and min_y <= y <= max_y :
          result = min(result, abs(x - sx))
      elif sy == ey :
        min_y, max_y = min(y, ay), max(y, ay)
        min_x, max_x = min(sx, ex), max(sx, ex)
        if min_y <= sy <= max_y and min_x <= x <= max_x :
          result = min(result, abs(y - sy))
          
  return result if result < MAX else 0
    
def solve() :
  cnt = 0
  x, y, r = 0, 0, 0
  for t, dir in rotate_list :
    t = int(t)
    ax, ay = x + dx[r]*t, y + dy[r]*t
    is_crash = find_crash(x, y, ax, ay, r)

    if is_crash :
      cnt += is_crash
      return cnt
    
    cnt += t
    line_list.insert(0, (x, y, ax, ay, r))
    x, y, r = ax, ay, ( r + next_dir[dir] ) % 4

  return cnt

print(solve())

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.