首页 > 试题广场 >

挡住洪水

[编程题]挡住洪水
  • 热度指数:4156 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
\hspace{15pt}吴铭市近日洪水肆虐,洪水从地图外部渗入。市政部门在若干方格上砌起围墙,用 `*` 表示。若某片空地区域不与地图边界四联通(上下左右方向),则不会被洪水淹没,视为安全空地。

\hspace{15pt}地图用大小为 x \times y 的字符矩阵描述:`'*'` 表示围墙,`'0'` 表示空地。所有相互四联通的 `'0'` 构成一个区域。请统计所有安全空地格子的数量之和(即所有不与边界四联通的 `'0'` 的总数)。

输入描述:
\hspace{15pt}第一行输入两个整数 x,y\left(1\leqq x,y\leqq 500\right)
\hspace{15pt}接下来 x 行,每行 y 个字符,组成围墙建设图,仅含 `'*'` 与 `'0'`。


输出描述:
\hspace{15pt}输出一个整数,表示所有安全空地格子的总数。
示例1

输入

2 2
**
**

输出

0
import sys
from collections import deque
global tmp_x, tmp_y
offsets = ((0, 1), (0, -1), (1, 0), (-1, 0))
# x,y是空地长和宽
data = sys.stdin.read().split()
idx = 0
x = int(data[idx]); idx += 1
y = int(data[idx]); idx += 1
grid = []
for i in range(x):
    grid.append(list(data[idx+i]))

# x, y = map(int, input().split())
# grid = [list(input()) for _ in range(x)]

def bfs(a, b):
    queue = deque([[a, b]])
    while queue:
        a, b = queue.popleft()
        grid[a][b] = '*'
        tmp_x.append(a)
        tmp_y.append(b)
        for dx, dy in offsets:
            new_a = a+dx; new_b = b+dy
            if 0 <= new_a < x and 0 <= new_b < y and grid[new_a][new_b] == '0':
                grid[new_a][new_b] = '*'
                queue.append([new_a, new_b])

ans = 0
for i in range(x):
    for j in range(y):
        if grid[i][j] == '0':
            tmp_x = []; tmp_y = []
            bfs(i, j)
            # 如果这块联通区域中的所有x,y都不在边界上,才认为是安全的。
            if min(tmp_x) > 0 and max(tmp_x) < x -1 and min(tmp_y) > 0 and max(tmp_y) < y -1:
                ans += len(tmp_x)
print(ans)
这个是统计0的个数,不是安全区域的个数,卡了我30分钟才发现
发表于 2026-03-06 01:32:17 回复(0)
from collections import deque
n,m = map(int,input().split())
grid = []
for i in range(n):
    grid.append(input().strip())
visited = [[False]*m for _ in range(n)]
dire = [(-1,0),(1,0),(0,-1),(0,1)]
cnt = 0
for i in range(n):
    for j in range(m):
        if grid[i][j] == '0' and not visited[i][j]:
            dq = deque([(i,j)])
            visited[i][j] = True
            is_safe = True
            size = 1
            while dq:
                x,y = dq.popleft()
                if x==0 or x==n-1 or y==0 or y==m-1:
                    is_safe = False
                for dx,dy in dire:
                    nx,ny=x+dx,y+dy
                    if 0<=nx<n and 0<=ny<m:
                        if not visited[nx][ny] and grid[nx][ny]=='0':
                            visited[nx][ny]=True
                            dq.append((nx,ny))
                            size += 1
            if is_safe:
                cnt +=size
print(cnt)
发表于 2025-09-04 19:26:34 回复(0)
这个题确实有歧义,这个地方统计的是安全区域中的0的个数
n,m = map(int, input().split())
if 1 <= n < 3&nbs***bsp;1 <= m < 3:
    print(0)
    quit()
s,dirs,sum1 = [],[(1,0),(0,1),(-1,0),(0,-1)],0
for i in range(n):
    s.append(list(input().replace('*','X')))      
def dfs(i,j):
    stack = [(i,j)]
    an = True
    shu = 1
    while stack:
        nx,ny = stack.pop()
        for dx,dy in dirs:
            x = nx+dx
            y = ny+dy
            if s[x][y] == '0':
                if x == 0&nbs***bsp;x == n-1&nbs***bsp;y == 0&nbs***bsp;y == m-1:
                    s[x][y] = 'X'
                    an = False
                elif 0 < x < n-1 and 0 < y < m-1:
                    s[x][y] = 'X'
                    shu += 1
                    stack.append((x,y))
    if an:
        return shu
    else:
        return 0
for i in range(n):
    for j in range(m):
        if s[i][j] == '0' and 0 < i < n-1 and 0 < j < m-1:
            s[i][j] = 'X'
            sum1 += dfs(i,j)
print(sum1)
首先n和m随便一个小于3都绝对不行,因为这个题的在边界上所有的0都会导致区域无效,因为只需要解决一次案例所以我用的quit直接退出,如果数据组数很多就不要这样做。然后就是经典的列表、dirs方向和和sum1。为了在过程中输出矩阵内容更直观,我把*换成了X,这样所有的元素都会很齐整。然后就是绝对dfs加栈遍历,对每一个dfs(i,j)记为一个区域,所以开头就写出an和shu,之后不用管s[x][y]为X的情况,因为对题目没有如何影响,你可以想一想,假如有一个区域含0,他不是安全区域的可能只有有边界0的情况,不然就一定是安全的,所以判断边界,如果不是边界就计数并append方便循环,最后return 0 或者 shu也是经典方法了,这样方便sun1累加。注意最后一定要是0而且不是边界的时候才dfs,这是寻找安全区域的基本条件,并且就是因为提前找到了一个0,dfs中shu必须从1开始

发表于 2025-08-17 11:35:57 回复(0)