Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

25-LJEDD2 #98

Merged
merged 8 commits into from
Mar 17, 2024
Merged

25-LJEDD2 #98

merged 8 commits into from
Mar 17, 2024

Conversation

LJEDD2
Copy link
Collaborator

@LJEDD2 LJEDD2 commented Mar 13, 2024

🔗 문제 링크

백준 - 그래프 탐색 | 점프 게임

문제 설명

  • 지도는 총 2개의 줄로 나누어져 있으며, 각 줄은 N개의 칸으로 나누어져 있다.
  • 안전한 칸(1)은 유저가 이동할 수 있는 칸, 위험한 칸(0)은 이동할 수 없는 칸
  • 처음에 유저는 왼쪽 줄의 1번 칸 위에 서있으며 매 초마다 다음 세 가지 행동 중 하나를 해야한다.
    • 현재 있는 칸이 i번 칸이면, i+1번 칸으로 이동한다 (앞으로 이동)
    • 현재 있는 칸이 i번 칸이면, i-1번 칸으로 이동한다 (뒤로 이동)
    • 현재 있는 칸이 왼쪽 줄의 i번 칸이면, 오른쪽 줄의 i+k번 칸으로 이동해야 한다. (건너서 이동)
  • N번 칸보다 더 큰 칸으로 이동하는 경우에는 게임을 클리어했다고 간주한다. (N만 지나면 된다.)
  • 1초가 지날 때마다 한 칸씩 각 줄의 첫 칸이 사라지게 된다.
  • 게임을 클리어 할 수 있는지, 없는지 구한다.

제한 조건

  • N과 k가 주어진다. (1 ≤ N, k ≤ 100,000)
  • i번째 문자가 0인 경우에는 위험한 칸이고, 1인 경우에는 안전한 칸
  • 왼쪽 줄의 1번 칸은 항상 안전한 칸

✔️ 소요된 시간

2시간

✨ 수도 코드

1. 문제 지문 이해하기

  • 문제 설명대로 동작하는 과정을 그려보면 다음과 같을 것이다.
    image

2. 문제 설명 따라 구현하기

  • 시간이 1초 흐를 때마다 맵이 좁아진다.
    • 맵이 1초에 1칸씩 없어질 때 이동 가능한 범위가 줄어드는 것을 함께 판단해줄 수 있을 것이다.
  • 없어진 칸으로는 사람이 갈 수 없다는 것을 고려해주면 풀 수 있는 문제이다.
  • 시간이 1초 흐를 때 저장되는 queue를 하나의 레벨로 두고 3가지의 이동 방법에 따라 이동 가능한 위치의 좌표를 계속해서 저장해나간다.

2.-1 시간에 따라 좁아지는 맵

  • 가장 왼쪽부터 한 줄씩 이동 가능한 칸이 사라진다.
  • 하나의 레벨이 끝날 때 초 카운트를 올려주고 그만큼 범위를 줄여준다.
    • 원래 자주 썼던 OOB()에서는 보통 주어지는 범위 내에 포함되는지를 판단하도록 구현했지만, 여기서는 time이 index의 역할을 하기도 하므로 time < col < N 으로 매번 범위 조건이 바뀌도록 구현하였다.
def OOB(y,time):
    return not(time < y < n) # 그냥 가능 범위를 제한해주면 되지 않을까?

2-2. 3가지의 이동 방법

  • 각 레벨에 따라 앞으로 가거나, 뒤로 가거나, 반대편으로 건너서 K칸 만큼 이동하거나의 총 3가지의 방법으로 이동할 수 있다.
  • 물결표시 ~ 를 사용해서 원래 데이터의 반대되는 데이터로 바꿔줄 수 있다.
  • 시간 제한에 걸리지 않으면서도 이동이 가능한 안전한 장소라면 건너가고 다시 방문하지 않도록 체크해주었다.
  • col index가 N을 넘어가게 된다면 True를 출력하고 프로그램을 종료하면 된다.
for nrow, ncol in ((row, col+1),(row, col-1),(~row, col+k)):

3. 최종 코드

from collections import deque
from sys import stdin

# Cur_X가 N을 넘어간다면 클리어

n,k = map(int,input().split())
board = [list(map(int, stdin.readline().strip())) for _ in range(2)]
visited = [[0] * n for _ in range(2)]

def OOB(y,time):
    return not(time < y < n) # 그냥 가능 범위를 제한해주면 되지 않을까?
def jump(start):
    queue = deque([start])
    time = 0
    while queue:
        # https://dirmathfl.tistory.com/184
        for _ in range(len(queue)): #  한 번에 한 "레벨"씩만 방문
            row,col = queue.popleft()
            # if time > 0:
            #     board[0][time] = 0
            #     board[1][time] = 0
            # if col >= n-1 or col + k >= n:
            #     return True

            for nrow, ncol in ((row, col+1),(row, col-1),(~row, col+k)): # ~ 하면 0과 1 스위칭가능
                # 3번 조건이 문제네
                if ncol >= n:
                    return print(1)

                if not OOB(ncol,time) and board[nrow][ncol] and not visited[nrow][ncol]:
                    visited[nrow][ncol] = 1
                    queue.append((nrow,ncol))

        time += 1
    return print(0)

start = [0,0]
jump(start)

📚 새롭게 알게된 내용

@LJEDD2 LJEDD2 self-assigned this Mar 13, 2024
@LJEDD2 LJEDD2 marked this pull request as draft March 13, 2024 13:23
@LJEDD2 LJEDD2 marked this pull request as ready for review March 14, 2024 04:02
@9kyo-hwang
Copy link
Contributor

흠 저는 엉뚱한 데서 해멨네요...

항상 row, col 값을 꺼내는 파트에서 큐 반복문 break 조건을 걸었었는데, 이 문제는 nrow, ncol 값을 꺼낼 때 검사하는 게 더 합리적이네요...

제 경우 아예 바깥 반복문을 tick이란 일종의 시간 카운팅 느낌의 반복문으로 설정해서 tick 값을 이용해 원본 줄 정보를 해당 시간마다 무너지도록 설정했습니다.

from collections import deque
input = open(0).readline

N, k = map(int, input().split())
lines = [list(map(int, input().rstrip())) for _ in range(2)]


def out_of_bound(c) -> bool:
    return not (0 <= c < N)


def bfs() -> bool:
    q = deque([(0, 0)])
    for tick in range(0, N):
        for _ in range(len(q)):
            r, c = q.popleft()
            
            lines[0][tick] = 0  # 다음 칸으로 갈 꺼니까
            lines[1][tick] = 0  # 이 시간 부로 현재 칸은 무너진다
            
            for nr, nc in ((r, c + 1), (r, c - 1), (r ^ 1, c + k)):
                if nc >= N:
                    return True
                
                if out_of_bound(nc) or lines[nr][nc] == 0:
                    continue
                
                lines[nr][nc] = 0
                q.append((nr, nc))

    return False


print(1 if bfs() else 0)

@LJEDD2
Copy link
Collaborator Author

LJEDD2 commented Mar 15, 2024

흠 저는 엉뚱한 데서 해멨네요...

항상 row, col 값을 꺼내는 파트에서 큐 반복문 break 조건을 걸었었는데, 이 문제는 nrow, ncol 값을 꺼낼 때 검사하는 게 더 합리적이네요...

제 경우 아예 바깥 반복문을 tick이란 일종의 시간 카운팅 느낌의 반복문으로 설정해서 tick 값을 이용해 원본 줄 정보를 해당 시간마다 무너지도록 설정했습니다.

와 ! 외쳐 갓교황 !
시간마다 앞에서 무너지도록 구현해볼라고 했다가 장렬하게 실패해버렸는데 ㅜㅜㅜㅜㅜ
이렇게 한번 풀어보겠습니다 쵝오

# if col >= n-1 or col + k >= n:
# return True

for nrow, ncol in ((row, col+1),(row, col-1),(~row, col+k)): # ~ 사용하면 0과 1 스위칭가능
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

비트연산자로 스위칭하는 !!!! 아이디어 좋습니다🤔🤔🤔👍
사실 비트연산자라는게 있다~ 라고만 들었지 실제로 사용한 적은 한번도 없었는데요,
정은님의 코드에서 0과 1을 스위치할 때 사용하는 걸 보고 다음에 저도 이런 경우가 생긴다면 꼭꼭꼮 활용해보겠습니다!!

Copy link
Member

@janghw0126 janghw0126 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

예린님이 말씀하셨던 비트 연산자를 활용하는 아이디어가 저도 인상깊었습니다!
저도 다음에 0과 1을 스위칭하는 경우가 생기면 꼭꼭 활용해보도록 하죠😎

visited = [[0] * n for _ in range(2)]

def OOB(y,time):
return not(time < y < n) # 그냥 time도 포함해서 접근 가능 범위를 제한해주면 되지 않을까?
Copy link
Member

@janghw0126 janghw0126 Mar 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오옷 이 아이디어는 생각해본 적이 없는데 매번 범위 조건이 바뀌도록 반환하는 방법이 있었군요!
다음에 함수를 작성할 때 비슷한 상황이 생기면 이렇게 써보도록 하겠습니닷

# if col >= n-1 or col + k >= n:
# return True

for nrow, ncol in ((row, col+1),(row, col-1),(~row, col+k)): # ~ 사용하면 0과 1 스위칭가능
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dfs에서 상하좌우할 때도 이런 방식으로 했었던 것 같은데 요번에 비트연산자를 활용해서 해주니 또 처음보는 것 같네요 😂 이번 기회로 다시 머리에 새기고 갑니다 ☺︎☻

@LJEDD2 LJEDD2 merged commit 37005f7 into main Mar 17, 2024
@LJEDD2 LJEDD2 deleted the 25-LJEDD2 branch March 17, 2024 15:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants