step vs counting cells

bomi ·2024년 7월 6일

algorithm

목록 보기
6/6

queue 안에서 count + 1을 하는 것은 BFS 탐색에서 각 단계의 깊이를 세는 것이고, queue 밖에서 count를 증가시키는 것은 연결된 셀(또는 노드)의 수를 세는 것입니다.

단계(step)를 세는 경우:
단계 수는 BFS에서 시작점으로부터 얼마나 많은 단계가 필요한지(즉, 몇 번의 이동이 필요한지)를 세는 것입니다. 이는 보통 최단 경로 문제에서 사용됩니다.

연결된 셀(cell)을 세는 경우:
연결된 셀의 수를 세는 것은 주어진 시작점에서 연결된 모든 셀의 수를 세는 것입니다. 이는 보통 연결된 컴포넌트를 찾는 문제에서 사용됩니다.

코드에서 단계(step)를 세는 것과 연결된 셀(cell)을 세는 것의 차이를 명확히 하기 위해, 두 경우의 예시를 보여드리겠습니다.

단계(step)를 세는 BFS 예시:

이 경우는 최단 경로를 찾는 문제에서 사용됩니다. 예를 들어, 미로의 시작점에서 출구까지 가는 최단 경로를 찾는 문제입니다.

def bfs_count_steps(x, y):
    queue = deque([(x, y, 0)])  # 세 번째 값이 단계 수를 나타냅니다.
    visited = [[False] * N for _ in range(N)]
    visited[x][y] = True
    
    while queue:
        x, y, steps = queue.popleft()
        for dx, dy in directions:
            nx, ny = x + dx, y + dy
            if 0 <= nx < N and 0 <= ny < N and grid[nx][ny] == 1 and not visited[nx][ny]:
                visited[nx][ny] = True
                queue.append((nx, ny, steps + 1))
                # 여기서는 steps + 1 을 통해 단계를 세고 있습니다.
                
    return steps  # 마지막 단계 수를 반환합니다.

연결된 셀(cell)을 세는 BFS 예시:

이 경우는 연결된 컴포넌트의 크기를 찾는 문제에서 사용됩니다. 예를 들어, 섬의 크기를 찾는 문제입니다.

def bfs_count_cells(x, y):
    queue = deque([(x, y)])
    visited[x][y] = True
    count = 1  # 처음 시작점을 포함하여 셀의 수를 세기 시작합니다.
    
    while queue:
        x, y = queue.popleft()
        for dx, dy in directions:
            nx, ny = x + dx, y + dy
            if 0 <= nx < N and 0 <= ny < N and grid[nx][ny] == 1 and not visited[nx][ny]:
                visited[nx][ny] = True
                queue.append((nx, ny))
                count += 1  # 연결된 셀의 수를 세기 위해 count를 증가시킵니다.
    
    return count  # 연결된 셀의 총 수를 반환합니다.
from collections import deque

def bfs_shortest_distance(start_x, start_y, target_x, target_y):
    # 시작점이 목표점과 동일한 경우 바로 0 반환
    if (start_x, start_y) == (target_x, target_y):
        return 0

    queue = deque([(start_x, start_y, 0)])  # 큐에 (x, y, distance) 형태로 삽입
    visited[start_x][start_y] = True

    while queue:
        x, y, distance = queue.popleft()
        
        # 네 방향으로 탐색
        for dx, dy in directions:
            nx, ny = x + dx, y + dy

            if 0 <= nx < N and 0 <= ny < N and not visited[nx][ny] and grid[nx][ny] == 1:
                if (nx, ny) == (target_x, target_y):
                    return distance + 1  # 목표 지점에 도달하면 최단 거리 반환
                queue.append((nx, ny, distance + 1))
                visited[nx][ny] = True

    return -1  # 목표 지점에 도달할 수 없는 경우

visited 배열을 언제 함수 밖에서 선언해야 하고, 언제 함수 안에서 선언해야 하는지에 대한 기준은 문제의 요구사항과 BFS의 목적에 따라 달라집니다.

1. visited 배열을 함수 밖에서 선언하는 경우:

목적: 연결된 컴포넌트를 찾기 위해 여러 번 BFS를 호출할 때
문제의 요구사항: 여러 시작점에서 BFS를 수행해야 하고, 방문 여부를 전역적으로 관리해야 할 때
사용 예시: 섬의 개수를 세거나 연결된 영역의 크기를 측정할 때

2. visited 배열을 함수 안에서 선언하는 경우:

목적: 단일 시작점에서 BFS를 수행할 때
문제의 요구사항: 단일 시작점에서 BFS를 수행하여 최단 경로를 찾거나, 특정 조건을 만족하는지 확인할 때
사용 예시: 미로에서 출발점에서 목표점까지의 최단 경로를 찾을 때

요약
함수 밖에서 선언: 여러 시작점에서 BFS를 수행하고 전역적인 방문 여부를 관리해야 할 때 (visited가 전역적으로 필요할 때).
함수 안에서 선언: 단일 시작점에서 BFS를 수행하고 방문 여부를 해당 BFS 호출에 대해서만 관리할 때 (visited가 지역적으로 필요할 때).

Great observation! The reason visited is being re-initialized inside the bfs function is because we need to reset the visited status for each new BFS call when we are searching for a different bundle of bombs. Each BFS search is independent, and we don't want the visited status from previous searches to interfere with the current one.

Let's break it down:

Why Re-initialize visited in Each BFS Call?

  1. Independent BFS Searches: Each time we call bfs, we are exploring a new potential bomb bundle starting from a new unvisited bomb. We need to start with a clean slate, where no cells are marked as visited, to correctly find all connected bombs of the same color (or bombs that include red bombs).
  2. Tracking Different Bomb Bundles Separately: The purpose of visited within the bfs function is to track the bombs that belong to the specific bundle we are currently exploring. Once we finish the BFS for a particular bomb bundle, we reset visited to ensure that when we start exploring another bundle, we don’t mistakenly think some cells are already visited when they’re not.

What Happens if We Don’t Re-initialize visited?

If we don’t reset visited within each BFS call, then cells visited in previous BFS calls will remain marked as visited. This means that when searching for the next bundle, those cells will be ignored, leading to incorrect results.

How visited Is Used:

  • During the BFS traversal, visited keeps track of which cells have been visited as part of the current bundle exploration.

  • After the BFS traversal is complete, and the bundle information is returned, visited is reset for the next bundle exploration.

Example Scenario:

Imagine we have multiple bomb bundles on the grid. If we don't reset visited, the first BFS might mark several cells as visited, which could cause the second BFS to miss part of a valid bomb bundle because it incorrectly believes those cells have already been processed.

When to Keep Track Globally?

You would use a global visited array without resetting if you wanted to mark cells permanently (e.g., in algorithms like flood fill where you want to mark areas as processed once and for all). However, in this case, we're interested in exploring independent connected components (bomb bundles) separately.

Summary:

The re-initialization of visited within each BFS is crucial to ensure each search for a bomb bundle is independent and accurate. This allows the function to correctly identify all possible bomb bundles without interference from previous searches.

0개의 댓글