【哈希-简单】463. 岛屿的周长

给定一个二维网格地图,其中1表示陆地,0表示水域,岛屿由相邻的陆地组成。任务是计算岛屿的周长,即陆地边缘与水域或地图边缘相接的边数。提供两种解决方案:一种是通过移动方向检查每个陆地格子的相邻格子;另一种是使用深度优先搜索(DFS)遍历岛屿。示例展示了不同输入下岛屿的周长计算结果。

【题目】
给定一个 row x col 的二维网格地图 grid ,其中:grid[i][j] = 1 表示陆地, grid[i][j] = 0 表示水域。
网格中的格子 水平和垂直 方向相连(对角线方向不相连)。整个网格被水完全包围,但其中恰好有一个岛屿(或者说,一个或多个表示陆地的格子相连组成的岛屿)。
岛屿中没有“湖”(“湖” 指水域在岛屿内部且不和岛屿周围的水相连)。格子是边长为 1 的正方形。网格为长方形,且宽度和高度均不超过 100 。计算这个岛屿的周长。
【示例 1】
输入:grid = [[0,1,0,0],[1,1,1,0],[0,1,0,0],[1,1,0,0]]
输出:16
解释:它的周长是上面图片中的 16 个黄色的边
【示例 2】
输入:grid = [[1]]
输出:4
【示例 3】
输入:grid = [[1,0]]
输出:4
【提示】
row == grid.length
col == grid[i].length
1 <= row, col <= 100
grid[i][j] 为 0 或 1
【代码】
【Python】

class Solution:
    def islandPerimeter(self, grid: List[List[int]]) -> int:
        cnt=0
        row,col=len(grid),len(grid[0])
        move=[[1,0],[0,1],[-1,0],[0,-1]]    #左右上下 四个方位移动
        for i in range(row):
            for j in range(col):
                if grid[i][j]:
                    cnt+=4
                    for k in range(4):
                        if (i+move[k][0])>=0 and (i+move[k][0])<row and (j+move[k][1])>=0 and (j+move[k][1])<col:
                            if grid[i+move[k][0]][j+move[k][1]]:
                                cnt-=1
        return cnt

【DFS】

class Solution:
    def islandPerimeter(self, grid: List[List[int]]) -> int:
        def dfs(grid,i,j):
            if i<0 or i>=len(grid) or j<0 or j>=len(grid[0]):
                return 1
            # 当前正好越界,说明穿过了一个边界,周长+1
            if grid[i][j]==0:
                return 1
            # 从土地来到了海水,说明穿过了一个边界,周长+1
            if grid[i][j]==2:
                return 0
			# 之前访问过,直接返回,返回0,无周长收益
            grid[i][j]=2
            # 到此,当前点为1,将它改为2,代表已访问
            return dfs(grid,i+1,j)+dfs(grid,i-1,j)+dfs(grid,i,j+1)+dfs(grid,i,j-1)

        for i in range(len(grid)):
            for j in range(len(grid[0])):
                if grid[i][j]:
                    return dfs(grid,i,j)
        return 0
import numpy as np import pandas as pd import re from openpyxl import load_workbook import math def read_until_blank_row(file_path, sheet_name, col_index=0): """ 读取Excel表中从第2行开始的数据,直到连续两列为空为止。 根据sheet名不同处理格式,并返回分段的点集列表。 返回: List[List[List[float]]] —— 每个子列表是一组 [[x1,y1], [x2,y2], ...] """ wb = load_workbook(filename=file_path, read_only=True) ws = wb[sheet_name] # Step 1: 确定有效数据行数(检查col_index+1 和 col_index+2列是否同时为空) data_rows_count = 0 for row in ws.iter_rows( min_row=2, min_col=col_index + 1, max_col=col_index + 2, values_only=True ): cell_value1, cell_value2 = row[0], row[1] if (cell_value1 is None or str(cell_value1).strip() == '') and \ (cell_value2 is None or str(cell_value2).strip() == ''): break data_rows_count += 1 wb.close() if data_rows_count == 0: return [] # 读取指定列 df = pd.read_excel( file_path, sheet_name=sheet_name, header=0, usecols=[col_index], engine='openpyxl', nrows=data_rows_count + 1 ) segments = [] # 存储所有段 current_segment = [] seen_in_current = set() # 当前段去重(避免重复点) coord_pattern = r'\{([^}]+)\}' # 匹配 {x, y, z} # 遍历每一行(跳过表头) for item in df.iloc[:, 0].tolist(): if pd.isna(item): continue text = str(item).strip() match = re.search(coord_pattern, text) if match: # 提取 { } 内容并解析为 x, y coords_str = match.group(1) parts = [p.strip() for p in coords_str.split(',')] try: x, y = float(parts[0]), float(parts[1]) pt_tuple = (round(x, 6), round(y, 6)) # 浮点精度控制 + 可哈希 # 若当前段为空 或 当前点不同于上一个点,则添加 if not current_segment or pt_tuple != tuple(current_segment[-1]): current_segment.append([x, y]) seen_in_current.add(pt_tuple) except (ValueError, IndexError): continue # 忽略无法解析的行 else: # 非坐标内容 → 视为段落分隔符 if len(current_segment) >= 3: # 至少3个点才能形成区域 segments.append(current_segment) current_segment = [] seen_in_current = set() # 处理最后一段 if len(current_segment) >= 3: segments.append(current_segment) return segments def polygon_area(points): """ 使用鞋带公式计算多边形面积(绝对值) points: list of [x, y] """ n = len(points) area = 0.0 for i in range(n): x1, y1 = points[i] x2, y2 = points[(i + 1) % n] area += x1 * y2 - x2 * y1 return abs(area) / 2.0 def polygon_perimeter(points): """ 计算多边形周长 """ length = 0.0 n = len(points) for i in range(n): x1, y1 = points[i] x2, y2 = points[(i + 1) % n] dx, dy = x2 - x1, y2 - y1 length += math.sqrt(dx*dx + dy*dy) return length def compute_circularity_sum(segments): """ 对每个段计算 4πS / L² 并求和 """ total_score = 0.0 pi = math.pi for i, pts in enumerate(segments): if len(pts) < 3: continue S = polygon_area(pts) L = polygon_perimeter(pts) if L <= 0: continue circularity = (4 * pi * S) / (L * L) total_score += circularity return total_score # ================================ # 主程序执行 # ================================ file_path = r'C:/Users/jinx/Desktop/数学建模/F题/F题/江南古典园林美学特征建模附件/赛题F江南古典园林美学特征建模附件资料/1. 拙政园/4-拙政园数据坐标.xlsx' sheet_name_shan = '假山' sheet_name_shui = '水体' # 读取“假山”和“水体”的分段数据 segments_mountain = read_until_blank_row(file_path, sheet_name_shan, col_index=0) segments_water = read_until_blank_row(file_path, sheet_name_shui, col_index=0) # 计算总和 water_result = compute_circularity_sum(segments_water) mountain_result = compute_circularity_sum(segments_mountain) # 输出结果 print(f"所有‘假山’区域的 4πS/L² 为: {mountain_result:.6f}") print(f"所有‘水体’区域的 4πS/L² 总和为: {water_result:.6f}") 现考虑到水体可能存在中心岛,导致水体的每一段可能存在包含关系,需要加入判断,若某段坐标围成的区域内部无其余点则正常计算,若内部有其余点则将大的那段坐标点围成的面积减去小的那段坐标点围成的面积作为S,两段坐标围成的区域周长加起来作为L
09-24
import numpy as np import pandas as pd import re from openpyxl import load_workbook import math def read_until_blank_row(file_path, sheet_name, col_index=0): “”" 读取Excel表中从第2行开始的数据,直到连续两列为空为止。 根据sheet名不同处理格式,并返回分段的点集列表。 返回: List[List[List[float]]] —— 每个子列表是一组 [[x1,y1], [x2,y2], …] “”" wb = load_workbook(filename=file_path, read_only=True) ws = wb[sheet_name] # Step 1: 确定有效数据行数(检查col_index+1 和 col_index+2列是否同时为空) data_rows_count = 0 for row in ws.iter_rows( min_row=2, min_col=col_index + 1, max_col=col_index + 2, values_only=True ): cell_value1, cell_value2 = row[0], row[1] if (cell_value1 is None or str(cell_value1).strip() == '') and \ (cell_value2 is None or str(cell_value2).strip() == ''): break data_rows_count += 1 wb.close() if data_rows_count == 0: return [] # 读取指定列 df = pd.read_excel( file_path, sheet_name=sheet_name, header=0, usecols=[col_index], engine='openpyxl', nrows=data_rows_count + 1 ) segments = [] # 存储所有段 current_segment = [] seen_in_current = set() # 当前段去重(避免重复点) coord_pattern = r'\{([^}]+)\}' # 匹配 {x, y, z} # 遍历每一行(跳过表头) for item in df.iloc[:, 0].tolist(): if pd.isna(item): continue text = str(item).strip() match = re.search(coord_pattern, text) if match: # 提取 { } 内容并解析为 x, y coords_str = match.group(1) parts = [p.strip() for p in coords_str.split(',')] try: x, y = float(parts[0]), float(parts[1]) pt_tuple = (round(x, 6), round(y, 6)) # 浮点精度控制 + 可哈希 # 若当前段为空 或 当前点不同于上一个点,则添加 if not current_segment or pt_tuple != tuple(current_segment[-1]): current_segment.append([x, y]) seen_in_current.add(pt_tuple) except (ValueError, IndexError): continue # 忽略无法解析的行 else: # 非坐标内容 → 视为段落分隔符 if len(current_segment) >= 3: # 至少3个点才能形成区域 segments.append(current_segment) current_segment = [] seen_in_current = set() # 处理最后一段 if len(current_segment) >= 3: segments.append(current_segment) return segments def polygon_area(points): “”" 使用鞋带公式计算多边形面积(绝对值) points: list of [x, y] “”" n = len(points) area = 0.0 for i in range(n): x1, y1 = points[i] x2, y2 = points[(i + 1) % n] area += x1 * y2 - x2 * y1 return abs(area) / 2.0 def polygon_perimeter(points): “”" 计算多边形周长 “”" length = 0.0 n = len(points) for i in range(n): x1, y1 = points[i] x2, y2 = points[(i + 1) % n] dx, dy = x2 - x1, y2 - y1 length += math.sqrt(dxdx + dydy) return length def compute_circularity_sum(segments): “”" 对每个段计算 4πS / L² 并求和 “”" total_score = 0.0 pi = math.pi for i, pts in enumerate(segments): if len(pts) < 3: continue S = polygon_area(pts) L = polygon_perimeter(pts) if L <= 0: continue circularity = (4 * pi * S) / (L * L) total_score += circularity return total_score ================================ 主程序执行 ================================ file_path = r’C:/Users/jinx/Desktop/数学建模/F题/F题/江南古典园林美学特征建模附件/赛题F江南古典园林美学特征建模附件资料/1. 拙政园/4-拙政园数据坐标.xlsx’ sheet_name_shan = ‘假山’ sheet_name_shui = ‘水体’ 读取“假山”和“水体”的分段数据 segments_mountain = read_until_blank_row(file_path, sheet_name_shan, col_index=0) segments_water = read_until_blank_row(file_path, sheet_name_shui, col_index=0) 计算总和 water_result = compute_circularity_sum(segments_water) mountain_result = compute_circularity_sum(segments_mountain) 输出结果 print(f"所有‘假山’区域的 4πS/L² 为: {mountain_result:.6f}“) print(f"所有‘水体’区域的 4πS/L² 总和为: {water_result:.6f}”) 现考虑到水体可能存在中心岛,导致水体的每一段可能存在包含关系,需要加入判断,若某段坐标围成的区域内部无其余点则正常计算,若内部有其余点则将大的那段坐标点围成的面积减去小的那段坐标点围成的面积作为S,两段坐标围成的区域周长加起来作为L,且最后求和时不再计算被包围在内的那个区域
最新发布
09-24
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值