最大的湖
题目描述
运行代码
#include<iostream> using namespace std; bool mp[102][102]; int sum,num; int N,M,K; int dfs(int x,int y ) { if( mp[x][y] ) { mp[x][y]=0; sum++; dfs(x+1,y); dfs(x-1,y); dfs(x,y+1); dfs(x,y-1); } return 0; } int main() { cin>>N>>M>>K; int x,y; for( int i=1;i<=K;i++ ) { cin>>x>>y; mp[x][y]=1; } for( int i=1;i<=N;i++ ) { for( int j=1;j<=M;j++ ) { sum=0; dfs(i,j); num=max(num,sum); } } cout<<num; return 0; }
代码思路
- 初始化:
- 定义了一个二维数组
mp
,用于表示网格的状态,其中1表示已占用或可达的位置,0表示空位置。 - 定义了三个整数变量
sum
、num
和K
,以及两个整数变量N
和M
,分别用于表示当前连通块的大小、最大连通块的大小、已标记的位置数量、网格的行数和列数。
- 读取输入:
- 从标准输入读取网格的行数
N
、列数M
和已占用位置的个数K
。 - 使用循环读取
K
个已占用位置的坐标(x, y)
,并在mp
数组中将其标记为1。
- DFS遍历:
- 使用了两层嵌套循环遍历整个网格的每一个位置
(i, j)
。 - 对于每一个位置
(i, j)
,都重置sum
为0,然后调用dfs
函数来搜索以(i, j)
为起点的连通块大小。 dfs
函数递归地访问当前位置的上下左右四个相邻位置,如果相邻位置是已占用的(即mp[x][y]
为1),则将其标记为已访问(即mp[x][y]
设为0)并将sum
加1。然后继续递归访问该相邻位置的相邻位置。- 在每次
dfs
调用结束后,使用max
函数更新num
为当前连通块大小sum
和num
中的较大值。
- 输出结果:在遍历完整个网格后,输出最大连通块的大小
num
。
改进建议
问题
- 变量初始化:
num
没有初始化为0,这可能会导致未定义的行为,因为num
可能包含任意值。 - DFS逻辑:在
dfs
函数中,你递归地探索了当前位置的四个方向(上、下、左、右)。但是,你没有检查递归调用是否越界(即,是否仍然在网格内)。 - 不必要的重复计算:在
main
函数中,你使用了两层循环遍历整个网格,并对每个位置都调用dfs
。但是,一旦你找到一个1并调用了dfs
,你就不需要再次对同一个位置调用dfs
,因为该位置及其连通块已经被标记为0了。 - 性能问题:由于上述不必要的重复计算,该代码的性能非常差。
改进方向
- 初始化变量:在
main
函数的开始处,将num
初始化为0。 - 边界检查:在
dfs
函数中,添加边界检查以确保递归调用不会越界。 - 避免重复计算:在遍历网格时,只对值为1的位置调用
dfs
,并在调用后立即将其标记为已访问(例如,使用另一个布尔数组或将其值更改为一个特殊的“已访问”值)。 - 使用队列或栈进行BFS或DFS:虽然递归DFS在这里可以工作,但使用队列或栈可能会更清晰,并减少递归调用栈的深度。
改进代码
#include<iostream> #include<vector> #include<algorithm> using namespace std; bool mp[102][102]; bool visited[102][102]; // 用于标记已访问的位置 int maxArea = 0; void dfs(int x, int y, int& area, int N, int M) { if (x < 1 || x > N || y < 1 || y > M || !mp[x][y] || visited[x][y]) return; visited[x][y] = true; area++; dfs(x+1, y, area, N, M); dfs(x-1, y, area, N, M); dfs(x, y+1, area, N, M); dfs(x, y-1, area, N, M); } int main() { int N, M, K; cin >> N >> M >> K; int x, y; for (int i = 0; i < K; i++) { cin >> x >> y; mp[x][y] = true; } for (int i = 1; i <= N; i++) { for (int j = 1; j <= M; j++) { if (mp[i][j] && !visited[i][j]) { int area = 0; dfs(i, j, area, N, M); maxArea = max(maxArea, area); } } } cout << maxArea << endl; return 0; }
代码思路
- 初始化:
- 声明了两个二维数组
mp
和visited
,其中mp
用于存储网格的初始状态(0表示空,1表示占用),visited
用于标记在DFS过程中已经访问过的位置。 - 声明了一个变量
maxArea
来记录找到的最大连通块的大小,并将其初始化为0。
- 读取输入:
- 从输入中读取网格的维度
N
和M
,以及占用位置的个数K
。 - 对于每个占用位置,读取其坐标
(x, y)
,并在mp
数组中将其标记为1。
- DFS遍历:
- 使用两层循环遍历整个网格。
- 对于每个位置
(i, j)
,如果它是占用的(mp[i][j]
为1)且尚未被访问过(visited[i][j]
为false
),则调用DFS函数来搜索该位置所在的连通块。 - 在DFS函数中,首先检查当前位置
(x, y)
是否在网格内、是否被占用且未被访问过。如果是,则将其标记为已访问,并将当前连通块的大小加1。 - 然后,递归地调用DFS函数来搜索当前位置的上、下、左、右四个相邻位置。
- 每次DFS调用结束后,更新
maxArea
为当前连通块大小和maxArea
中的较大值。
- 输出结果:在遍历完整个网格后,输出找到的最大连通块的大小
maxArea
。
注意点:改进代码为 AI优化原代码