グラフ理論と行列操作アルゴリズム

100. 島の最大面積

与えられた1(陸地)と0(水)からなる行列において、島の最大面積を計算します。島は水平または垂直方向に隣接する陸地で構成され、周囲が水で囲まれているものとします。

from collections import deque

def max_area_of_island(grid):
    rows, cols = len(grid), len(grid[0])
    max_area = 0
    
    for i in range(rows):
        for j in range(cols):
            if grid[i][j] == 1:
                current_area = 0
                queue = deque([(i, j)])
                grid[i][j] = 0
                
                while queue:
                    x, y = queue.popleft()
                    current_area += 1
                    for dx, dy in [(0,1),(0,-1),(1,0),(-1,0)]:
                        nx, ny = x+dx, y+dy
                        if 0<=nx<rows and 0<=ny<cols and grid[nx][ny]==1:
                            grid[nx][ny] = 0
                            queue.append((nx, ny))
                max_area = max(max_area, current_area)
    return max_area
</code>

101. 孤立島の総面積

行列の端に接していない島(孤立島)の総面積を計算します。

def count_isolated_islands(matrix):
    rows, cols = len(matrix), len(matrix[0])
    
    def dfs(x, y):
        if x<0 or y<0 or x>=rows or y>=cols or matrix[x][y]!=1:
            return 0
        matrix[x][y] = 0
        area = 1
        for dx, dy in [(0,1),(0,-1),(1,0),(-1,0)]:
            area += dfs(x+dx, y+dy)
        return area
    
    total = 0
    for i in range(1, rows-1):
        for j in range(1, cols-1):
            if matrix[i][j] == 1:
                total += dfs(i, j)
    return total

102. 島の沈没

孤立島を水没させ(1を0に変更)、変更後の行列を出力します。

def sink_isolated_islands(grid):
    rows, cols = len(grid), len(grid[0])
    
    def mark_non_isolated(x, y):
        if 0<=x<rows and 0<=y<cols and grid[x][y]==1:
            grid[x][y] = 2
            for dx, dy in [(0,1),(0,-1),(1,0),(-1,0)]:
                mark_non_isolated(x+dx, y+dy)
    
    # 端の島をマーク
    for i in range(rows):
        mark_non_isolated(i, 0)
        mark_non_isolated(i, cols-1)
    for j in range(cols):
        mark_non_isolated(0, j)
        mark_non_isolated(rows-1, j)
    
    # 孤立島を沈没
    for i in range(rows):
        for j in range(cols):
            if grid[i][j] == 1:
                grid[i][j] = 0
            elif grid[i][j] == 2:
                grid[i][j] = 1
    return grid
</code>

103. 水流問題

特定のセルから水が両方の境界に到達できるかを判定します。

def water_flow(matrix):
    rows, cols = len(matrix), len(matrix[0])
    pacific = [[False]*cols for _ in range(rows)]
    atlantic = [[False]*cols for _ in range(rows)]
    
    def dfs(x, y, ocean):
        ocean[x][y] = True
        for dx, dy in [(0,1),(0,-1),(1,0),(-1,0)]:
            nx, ny = x+dx, y+dy
            if 0<=nx<rows and 0<=ny<cols and not ocean[nx][ny] and matrix[nx][ny]>=matrix[x][y]:
                dfs(nx, ny, ocean)
    
    # 太平洋(左と上)から到達可能なセル
    for i in range(rows):
        dfs(i, 0, pacific)
    for j in range(cols):
        dfs(0, j, pacific)
    
    # 大西洋(右と下)から到達可能なセル
    for i in range(rows):
        dfs(i, cols-1, atlantic)
    for j in range(cols):
        dfs(rows-1, j, atlantic)
    
    # 両方に到達可能なセルを返す
    return [(i,j) for i in range(rows) for j in range(cols) if pacific[i][j] and atlantic[i][j]]

104. 最大島の構築

1つの0を1に変更した後、可能な最大の島の面積を求めます。

def largest_island_after_flip(grid):
    rows, cols = len(grid), len(grid[0])
    island_id = 2
    area_map = {}
    
    def dfs(x, y, id):
        if x<0 or y<0 or x>=rows or y>=cols or grid[x][y]!=1:
            return 0
        grid[x][y] = id
        area = 1
        for dx, dy in [(0,1),(0,-1),(1,0),(-1,0)]:
            area += dfs(x+dx, y+dy, id)
        return area
    
    # 各島にIDを割り当てて面積を記録
    for i in range(rows):
        for j in range(cols):
            if grid[i][j] == 1:
                area = dfs(i, j, island_id)
                area_map[island_id] = area
                island_id += 1
    
    max_area = max(area_map.values()) if area_map else 0
    
    # 各0セルをチェック
    for i in range(rows):
        for j in range(cols):
            if grid[i][j] == 0:
                connected = set()
                for dx, dy in [(0,1),(0,-1),(1,0),(-1,0)]:
                    nx, ny = i+dx, j+dy
                    if 0<=nx<rows and 0<=ny<cols and grid[nx][ny]>1:
                        connected.add(grid[nx][ny])
                current = 1 + sum(area_map[id] for id in connected)
                max_area = max(max_area, current)
    return max_area

105. 有向グラフの到達可能性

ノード1から全てのノードに到達可能かどうかを判定します。

def is_fully_reachable(n, edges):
    graph = [[] for _ in range(n+1)]
    for s, t in edges:
        graph[s].append(t)
    
    visited = [False]*(n+1)
    queue = [1]
    visited[1] = True
    count = 1
    
    while queue:
        node = queue.pop()
        for neighbor in graph[node]:
            if not visited[neighbor]:
                visited[neighbor] = True
                count += 1
                queue.append(neighbor)
    
    return 1 if count == n else -1

106. 島の周長

島の周囲の長さを計算します。

def island_perimeter(grid):
    rows, cols = len(grid), len(grid[0])
    perimeter = 0
    
    for i in range(rows):
        for j in range(cols):
            if grid[i][j] == 1:
                perimeter += 4
                if i>0 and grid[i-1][j]==1:
                    perimeter -= 2
                if j>0 and grid[i][j-1]==1:
                    perimeter -= 2
    return perimeter

タグ: グラフ理論 行列操作 深さ優先探索 幅優先探索 動的計画法

6月18日 17:18 投稿