100. 岛屿的最大面积
卡码网题目链接(ACM模式)
题目描述
给定一个由 1(陆地)和 0(水)组成的矩阵,计算岛屿的最大面积。方岛屿面积的计算式为组成岛屿的陆地的总数。
岛屿由水平方向或垂直方向上相邻的陆地连接而成,并且四周都是水域。你可以假设矩阵外均被水包围。
输入描述
第一行包含两个整数 N, M,表示矩阵的行数和列数。后续 N 行,每行包含 M 个数字,数字为 1 或者 0,表示岛屿的单元格。
输出描述
输出一个整数,表示岛屿的最大面积。如果不存在岛屿,则输出 0。
输入示例
4 5
1 1 0 0 0
1 1 0 0 0
0 0 1 0 0
0 0 0 1 1
输出示例 4
提示信息
样例输入中,岛屿的最大面积为 4。
数据范围:
1 <= M, N <= 50。
思考
计算岛屿的最大面积: 岛屿由水平方向或垂直方向上相邻的陆地连接而成。
方岛屿面积的计算式为组成岛屿的陆地的总数: 几个陆地 = 几个面积
垂直、水平: 上下左右:[(0, 1), (0, -1), (-1, 0), (1, 0)]
# dfs bfs 都可以---目的找到当前的 (i, j)位置所连接(垂直 or 水平)的所有陆地。
邻接矩阵 : 1. dfs; 2. bfs
code python 1
# 先谋定 而后动
# dfs 需要面积,所以返回面积值
def dfs(graph, visited, result, x, y):
# 四个方向确定好
dir = [(0, 1), (0, -1), (-1, 0), (1, 0)]
# 遍历是个方向,收集结果,递归,回溯
for i in range(4):
nextx = x + dir[i][0]
nexty = y + dir[i][1]
if nextx < 0 or nexty < 0 or nextx >= len(graph) or nexty >= len(graph[0]): continue # 不满足条件
if not visited[nextx][nexty] and graph[nextx][nexty] == 1:
visited[nextx][nexty] = True
result[0] += 1
dfs(graph, visited, result, nextx, nexty) # visited被标记表示下一次不会在搜索它, 说明已经实现了遍历完的功能 而面积,就是在上一个的基础上叠加,所以不需要回溯
def main():
n, m = [int(v) for v in input().split(' ')]
graph = []
visited = [[False for _ in range(m)] for _ in range(n)]
n1 = n
while n1:
n1 -= 1
v = [int(v) for v in input().split(' ')]
graph.append(v)
areas = 0
for i in range(n):
for j in range(m):
if not visited[i][j] and graph[i][j] == 1:
visited[i][j] = True
res = [1]
dfs(graph, visited, res, i, j)
areas = max(res[0], areas)
print(areas)
main()
code python 2
# 先谋定 而后动
# dfs 需要面积,所以返回面积值
from collections import deque
def bfs(graph, visited, x, y):
# 四个方向确定好
dir = [(0, 1), (0, -1), (-1, 0), (1, 0)]
que = deque()
que.append([x, y])
result = 1
while que:
cur = que.popleft()
for i in range(4):
nextx = cur[0] + dir[i][0]
nexty = cur[1] + dir[i][1]
if nextx < 0 or nexty < 0 or nextx >= len(graph) or nexty >= len(graph[0]): continue # 不满足条件
if not visited[nextx][nexty] and graph[nextx][nexty] == 1: # 满足条件
visited[nextx][nexty] = True
result += 1
que.append([nextx,nexty])
return result
def main():
n, m = [int(v) for v in input().split(' ')]
graph = []
visited = [[False for _ in range(m)] for _ in range(n)]
n1 = n
while n1:
n1 -= 1
v = [int(v) for v in input().split(' ')]
graph.append(v)
areas = 0
for i in range(n):
for j in range(m):
if not visited[i][j] and graph[i][j] == 1:
visited[i][j] = True
res = bfs(graph, visited, i, j)
areas = max(res, areas)
print(areas)
main()
101. 孤岛的总面积
卡码网:101. 孤岛的总面积
题目描述
给定一个由 1(陆地)和 0(水)组成的矩阵,岛屿指的是由水平或垂直方向上相邻的陆地单元格组成的区域,
且完全被水域单元格包围。孤岛是那些位于矩阵内部、所有单元格都不接触边缘的岛屿。
现在你需要计算所有孤岛的总面积,岛屿面积的计算方式为组成岛屿的陆地的总数。
输入描述
第一行包含两个整数 N, M,表示矩阵的行数和列数。之后 N 行,每行包含 M 个数字,数字为 1 或者 0。
输出描述
输出一个整数,表示所有孤岛的总面积,如果不存在孤岛,则输出 0。
输入示例
4 5
1 1 0 0 0
1 1 0 0 0
0 0 1 0 0
0 0 0 1 1
输出示例:1
提示信息:
在矩阵中心部分的岛屿,因为没有任何一个单元格接触到矩阵边缘,所以该岛屿属于孤岛,总面积为 1。
数据范围:
1 <= M, N <= 50。
思考
孤岛是那些位于矩阵内部、所有单元格都不接触边缘的岛屿。
计算所有孤岛的总面积,岛屿面积的计算方式为组成岛屿的陆地的总数。
关键词: 在内部水平 or 垂直连接的最大面积。
--- 如果接触到边缘则面积记录为0
code python 1
# 先谋定 而后动
# dfs 需要面积,所以返回面积值
# flag:开始默认不在边缘
def dfs(graph, visited, result, flag, x, y):
# 四个方向确定好
dir = [(0, 1), (0, -1), (-1, 0), (1, 0)]
# 遍历是个方向,收集结果,递归,回溯
for i in range(4):
nextx = x + dir[i][0]
nexty = y + dir[i][1]
if nextx < 0 or nexty < 0 or nextx >= len(graph) or nexty >= len(graph[0]): continue # 不满足条件
if not visited[nextx][nexty] and graph[nextx][nexty] == 1:
if nextx == 0 or nexty == 0 or nextx == len(graph) -1 or nexty >= len(graph[0]) -1: # 有一个位置在边缘,使用flag进行标记
flag[0] = True
visited[nextx][nexty] = True
result[0] += 1
dfs(graph, visited, result, flag, nextx, nexty) # visited被标记表示下一次不会在搜索它, 说明已经实现了遍历完的功能 而面积,就是在上一个的基础上叠加,所以不需要回溯
def main():
n, m = [int(v) for v in input().split(' ')]
graph = []
visited = [[False for _ in range(m)] for _ in range(n)]
n1 = n
while n1:
n1 -= 1
v = [int(v) for v in input().split(' ')]
graph.append(v)
areas = 0
for i in range(n):
for j in range(m):
if not visited[i][j] and graph[i][j] == 1:
visited[i][j] = True
res = [1]
flag = [False]
dfs(graph, visited, res,flag, i, j)
if not flag[0]:
areas = max(res[0], areas) # 如果没有被标记在边缘, 在中间
print(areas)
main()
bfs 可行吗?
可行, 无论是哪个都只是为了找到当前的可行点能到达的所有可行点,同时标记是否为边缘
code python 2
# 先谋定 而后动
# dfs 需要面积,所以返回面积值
from collections import deque
def bfs(graph, visited, x, y):
# 四个方向确定好
dir = [(0, 1), (0, -1), (-1, 0), (1, 0)]
que = deque()
que.append([x, y])
result = 1
flag = False
while que:
cur = que.popleft()
for i in range(4):
nextx = cur[0] + dir[i][0]
nexty = cur[1] + dir[i][1]
if nextx < 0 or nexty < 0 or nextx >= len(graph) or nexty >= len(graph[0]): continue # 不满足条件
if not visited[nextx][nexty] and graph[nextx][nexty] == 1: # 满足条件
if nextx == 0 or nexty == 0 or nextx == len(graph) - 1 or nexty >= len(graph[0]) - 1: # 有一个位置在边缘,使用flag进行标记
flag = True
visited[nextx][nexty] = True
result += 1
que.append([nextx,nexty])
return flag, result
def main():
n, m = [int(v) for v in input().split(' ')]
graph = []
visited = [[False for _ in range(m)] for _ in range(n)]
n1 = n
while n1:
n1 -= 1
v = [int(v) for v in input().split(' ')]
graph.append(v)
areas = 0
for i in range(n):
for j in range(m):
if not visited[i][j] and graph[i][j] == 1:
visited[i][j] = True
flag, res = bfs(graph, visited, i, j)
if not flag:
areas = max(res, areas) # 如果没有被标记在边缘, 在中间
print(areas)
main()
思路2
本题使用dfs,bfs,并查集都是可以的。
本题要求找到不靠边的陆地面积,那么我们只要从周边找到陆地然后 通过 dfs或者bfs 将周边靠陆地且相邻的陆地都变成海洋,然
后再去重新遍历地图 统计此时还剩下的陆地就可以了。
如图,在遍历地图周围四个边,靠地图四边的陆地,都为绿色,
在遇到地图周边陆地的时候,将1都变为0,此时地图为这样:
然后我们再去遍历这个地图,遇到有陆地的地方,去采用深搜或者广搜,边统计所有陆地。
如果对深搜或者广搜不够了解,建议先看这里:深度优先搜索精讲,广度优先搜索精讲。
采用深度优先搜索的代码如下:
#include <iostream>
#include <vector>
using namespace std;
int dir[4][2] = {-1, 0, 0, -1, 1, 0, 0, 1}; // 保存四个方向
int count; // 统计符合题目要求的陆地空格数量
void dfs(vector<vector<int>>& grid, int x, int y) {
grid[x][y] = 0;
count++;
for (int i = 0; i < 4; i++) { // 向四个方向遍历
int nextx = x + dir[i][0];
int nexty = y + dir[i][1];
// 超过边界
if (nextx < 0 || nextx >= grid.size() || nexty < 0 || nexty >= grid[0].size()) continue;
// 不符合条件,不继续遍历
if (grid[nextx][nexty] == 0) continue;
dfs (grid, nextx, nexty);
}
return;
}
int main() {
int n, m;
cin >> n >> m;
vector<vector<int>> grid(n, vector<int>(m, 0));
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cin >> grid[i][j];
}
}
// 从左侧边,和右侧边 向中间遍历
for (int i = 0; i < n; i++) {
if (grid[i][0] == 1) dfs(grid, i, 0);
if (grid[i][m - 1] == 1) dfs(grid, i, m - 1);
}
// 从上边和下边 向中间遍历
for (int j = 0; j < m; j++) {
if (grid[0][j] == 1) dfs(grid, 0, j);
if (grid[n - 1][j] == 1) dfs(grid, n - 1, j);
}
count = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (grid[i][j] == 1) dfs(grid, i, j);
}
}
cout << count << endl;
}
//采用广度优先搜索的代码如下:
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
int count = 0;
int dir[4][2] = {0, 1, 1, 0, -1, 0, 0, -1}; // 四个方向
void bfs(vector<vector<int>>& grid, int x, int y) {
queue<pair<int, int>> que;
que.push({x, y});
grid[x][y] = 0; // 只要加入队列,立刻标记
count++;
while(!que.empty()) {
pair<int ,int> cur = que.front(); que.pop();
int curx = cur.first;
int cury = cur.second;
for (int i = 0; i < 4; i++) {
int nextx = curx + dir[i][0];
int nexty = cury + dir[i][1];
if (nextx < 0 || nextx >= grid.size() || nexty < 0 || nexty >= grid[0].size()) continue; // 越界了,直接跳过
if (grid[nextx][nexty] == 1) {
que.push({nextx, nexty});
count++;
grid[nextx][nexty] = 0; // 只要加入队列立刻标记
}
}
}
}
int main() {
int n, m;
cin >> n >> m;
vector<vector<int>> grid(n, vector<int>(m, 0));
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cin >> grid[i][j];
}
}
// 从左侧边,和右侧边 向中间遍历
for (int i = 0; i < n; i++) {
if (grid[i][0] == 1) bfs(grid, i, 0);
if (grid[i][m - 1] == 1) bfs(grid, i, m - 1);
}
// 从上边和下边 向中间遍历
for (int j = 0; j < m; j++) {
if (grid[0][j] == 1) bfs(grid, 0, j);
if (grid[n - 1][j] == 1) bfs(grid, n - 1, j);
}
count = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (grid[i][j] == 1) bfs(grid, i, j);
}
}
cout << count << endl;
}
102. 沉没孤岛
卡码网题目链接(ACM模式)
题目描述:
给定一个由 1(陆地)和 0(水)组成的矩阵,岛屿指的是由水平或垂直方向上相邻的陆地单元格组成的区域,且完全被水域单元格包围。
孤岛是那些位于矩阵内部、所有单元格都不接触边缘的岛屿。
现在你需要将所有孤岛“沉没”,即将孤岛中的所有陆地单元格(1)转变为水域单元格(0)。
输入描述:
第一行包含两个整数 N, M,表示矩阵的行数和列数。
之后 N 行,每行包含 M 个数字,数字为 1 或者 0,表示岛屿的单元格。
输出描述
输出将孤岛“沉没”之后的岛屿矩阵。
输入示例:
4 5
1 1 0 0 0
1 1 0 0 0
0 0 1 0 0
0 0 0 1 1
输出示例:
1 1 0 0 0
1 1 0 0 0
0 0 0 0 0
0 0 0 1 1
提示信息:
将孤岛沉没:
数据范围:
1 <= M, N <= 50
思路
将中间的 孤岛的位置变成0,
先把边缘的非孤岛用 2 表示, 再把中间的 1 变成 0, 再把2 变成 1.
所以 dfs bfs 都可以的。
code python 1 dfs
def dfs(graph, visited, x, y):
graph[x][y] = 2
dir = [(0, 1), (0, -1), (-1, 0), (1, 0)]
# 遍历是个方向,收集结果,递归,回溯
for i in range(4):
nextx = x + dir[i][0]
nexty = y + dir[i][1]
if nextx < 0 or nexty < 0 or nextx >= len(graph) or nexty >= len(graph[0]): continue # 不满足条件
if not visited[nextx][nexty] and graph[nextx][nexty] == 1:
visited[nextx][nexty] = True
dfs(graph, visited, nextx, nexty) # visited被标记表示下一次不会在搜索它, 说明已经实现了遍历完的功能 而面积,就是在上一个的基础上叠加,所以不需要回溯
def main():
n, m = [int(v) for v in input().split(' ')]
graph = []
visited = [[False for _ in range(m)] for _ in range(n)]
n1 = n
while n1:
n1 -= 1
v = [int(v) for v in input().split(' ')]
graph.append(v)
# 上边,下边
for j in range(m):
if graph[0][j] == 1: dfs(graph, visited, 0, j)
if graph[n-1][j] == 1: dfs(graph, visited, n-1, j)
# 左边、右边
for i in range(n):
if graph[i][0] == 1: dfs(graph, visited, i, 0)
if graph[i][m-1]==1:dfs(graph, visited, i, m-1)
# 把中间的孤岛变成 0
for i in range(1, n-1):
for j in range(1, m-1):
if graph[i][j] == 1:
graph[i][j] = 0
# 把边缘的岛屿 2 变成 1
for i in range(n):
for j in range(m):
if graph[i][j] == 2:
graph[i][j] = 1
# 打印出最后的岛屿
for v in graph:
for i in v[:-1]:
print(i, end=' ')
print(v[-1])
main()
code python 2 bfs
## code python 2
# 先谋定 而后动
# dfs 需要面积,所以返回面积值
from collections import deque
def bfs(graph, visited, x, y):
# 四个方向确定好
dir = [(0, 1), (0, -1), (-1, 0), (1, 0)]
que = deque()
graph[x][y] = 2
que.append([x, y])
while que:
cur = que.popleft()
for i in range(4):
nextx = cur[0] + dir[i][0]
nexty = cur[1] + dir[i][1]
if nextx < 0 or nexty < 0 or nextx >= len(graph) or nexty >= len(graph[0]): continue # 不满足条件
if not visited[nextx][nexty] and graph[nextx][nexty] == 1: # 满足条件
visited[nextx][nexty] = True
graph[nextx][nexty] = 2
que.append([nextx,nexty])
def main():
n, m = [int(v) for v in input().split(' ')]
graph = []
visited = [[False for _ in range(m)] for _ in range(n)]
n1 = n
while n1:
n1 -= 1
v = [int(v) for v in input().split(' ')]
graph.append(v)
# 上边,下边
for j in range(m):
if graph[0][j] == 1: bfs(graph, visited, 0, j)
if graph[n-1][j] == 1: bfs(graph, visited, n-1, j)
# 左边、右边
for i in range(n):
if graph[i][0] == 1: bfs(graph, visited, i, 0)
if graph[i][m-1]==1:bfs(graph, visited, i, m-1)
# 把中间的孤岛变成 0
for i in range(1, n-1):
for j in range(1, m-1):
if graph[i][j] == 1:
graph[i][j] = 0
# 把边缘的岛屿 2 变成 1
for i in range(n):
for j in range(m):
if graph[i][j] == 2:
graph[i][j] = 1
# 打印出最后的岛屿
for v in graph:
for i in v[:-1]:
print(i, end=' ')
print(v[-1])
main()
103. 水流问题
卡码网题目链接(ACM模式)
题目描述:
现有一个 N × M 的矩阵,每个单元格包含一个数值,这个数值代表该位置的相对高度。矩阵的左边界和上边界被认为是第一组边界,而矩阵的右边界和下边界被视为第二组边界。
矩阵模拟了一个地形,当雨水落在上面时,水会根据地形的倾斜向低处流动,但只能从较高或等高的地点流向较低或等高并且相邻(上下左右方向)的地点。
我们的目标是确定那些单元格,从这些单元格出发的水可以达到第一组边界和第二组边界。
输入描述:
第一行包含两个整数 N 和 M,分别表示矩阵的行数和列数。
后续 N 行,每行包含 M 个整数,表示矩阵中的每个单元格的高度。
输出描述:
输出共有多行,每行输出两个整数,用一个空格隔开,表示可达第一组边界和第二组边界的单元格的坐标,输出顺序任意。
输入示例:
5 5
1 3 1 2 4
1 2 1 3 2
2 4 7 2 1
4 5 6 1 1
1 4 1 2 1
输出示例:
0 4
1 3
2 2
3 0
3 1
3 2
4 0
4 1
提示信息:
图中的蓝色方块上的雨水既能流向第一组边界,也能流向第二组边界。所以最终答案为所有蓝色方块的坐标。
数据范围:
1 <= M, N <= 50
思路
从这些单元格出发的水可以达到第一组边界和第二组边界。
矩阵的左边界和上边界被认为是第一组边界,
而矩阵的右边界和下边界被视为第二组边界。
flag1 = 第一边界
flag2 = 第二边界
code python 1 dfs
# 先谋定 而后动
# dfs 需要面积,所以返回面积值
def dfs(graph, visited, flag1, flag2, x, y):
"""
四个方向: 如果值 <= graph(x,j),则继续搜索
如果有一个值到达第一边界 则 flag = True
如果一个值到达第二边界 则 flag2 = True
"""
dir = [(0, 1), (0, -1), (-1, 0), (1, 0)]
# 遍历是个方向,收集结果,递归,回溯
for i in range(4):
nextx = x + dir[i][0]
nexty = y + dir[i][1]
if nextx < 0 or nexty < 0 or nextx >= len(graph) or nexty >= len(graph[0]): continue # 不满足条件
if not visited[nextx][nexty] and graph[nextx][nexty] <= graph[x][y]: # 可以流过改点
visited[nextx][nexty] = True
if nextx == 0 or nexty == 0:
flag1[0] = True
if nextx == len(graph)-1 or nexty == len(graph[0]) - 1:
flag2[0] = True
dfs(graph, visited, flag1, flag2, nextx, nexty) # visited被标记表示下一次不会在搜索它, 说明已经实现了遍历完的功能 而面积,就是在上一个的基础上叠加,所以不需要回溯
def main():
n, m = [int(v) for v in input().split(' ')]
graph = []
n1 = n
while n1:
n1 -= 1
v = [int(v) for v in input().split(' ')]
graph.append(v)
result = []
for i in range(n):
for j in range(m):
flag1 = [False]
flag2 = [False]
visited = [[False for _ in range(m)] for _ in range(n)]
visited[i][j] = True
if i == 0 or j == 0:
flag1[0] = True
if i == len(graph) - 1 or j == len(graph[0]) - 1:
flag2[0] = True
dfs(graph, visited, flag1, flag2, i, j)
if flag1[0] and flag2[0]:
result.append([i, j])
# 输出
if result:
for v in result:
print(v[0], end = ' ')
print(v[1])
main()
code python 2 bfs
# 先谋定 而后动
# dfs 需要面积,所以返回面积值
from collections import deque
def bfs(graph, visited, x, y):
# 四个方向确定好
dir = [(0, 1), (0, -1), (-1, 0), (1, 0)]
que = deque()
que.append([x, y])
flag1,flag2 = False, False
while que:
cur = que.popleft()
for i in range(4):
nextx = cur[0] + dir[i][0]
nexty = cur[1] + dir[i][1]
if nextx < 0 or nexty < 0 or nextx >= len(graph) or nexty >= len(graph[0]): continue # 不满足条件
if not visited[nextx][nexty] and graph[nextx][nexty] <= graph[cur[0]][cur[1]]: # 满足条件
visited[nextx][nexty] = True
if nextx == 0 or nexty == 0:
flag1 = True
if nextx == len(graph) - 1 or nexty == len(graph[0]) - 1:
flag2 = True
if flag1 and flag2:return True, True
que.append([nextx, nexty])
return flag1, flag2
def main():
n, m = [int(v) for v in input().split(' ')]
graph = []
n1 = n
while n1:
n1 -= 1
v = [int(v) for v in input().split(' ')]
graph.append(v)
result = []
for i in range(n):
for j in range(m):
flag1 = False
flag2 = False
visited = [[False for _ in range(m)] for _ in range(n)]
visited[i][j] = True
if i == 0 or j == 0:
flag1 = True
if i == len(graph) - 1 or j == len(graph[0]) - 1:
flag2 = True
if flag1 and flag2:
result.append([i, j])
else:
flag1, flag2 = bfs(graph, visited, i, j)
if flag1 and flag2:
result.append([i, j])
# 输出
if result:
for v in result:
print(v[0], end = ' ')
print(v[1])
main()
优化 来自代码随想录
那么我们可以 反过来想,从第一组边界上的节点 逆流而上,将遍历过的节点都标记上。
同样从第二组边界的边上节点 逆流而上,将遍历过的节点也标记上。
然后两方都标记过的节点就是既可以流 太平洋 也可以流大西洋的节点。
从第一组边界边上节点出发,如图
code python 3 dfs
## code python 2 bfs
# 先谋定 而后动
# dfs 标定可达 逆流而上
def dfs1(graph, visited, x, y):
"""
四个方向: 如果值 <= graph(x,j),则继续搜索
如果有一个值到达第一边界 则 flag = True
如果一个值到达第二边界 则 flag2 = True
"""
visited[x][y] = True
dir = [(0, 1), (0, -1), (-1, 0), (1, 0)]
# 遍历是个方向,收集结果,递归,回溯
for i in range(4):
nextx = x + dir[i][0]
nexty = y + dir[i][1]
if nextx < 0 or nexty < 0 or nextx >= len(graph) or nexty >= len(graph[0]): continue # 不满足条件
if not visited[nextx][nexty] and graph[nextx][nexty] >= graph[x][y]: # 可以流过改点
dfs(graph, visited, nextx, nexty) # visited被标记表示下一次不会在搜索它, 说明已经实现了遍历完的功能 而面积,就是在上一个的基础上叠加,所以不需要回溯
def dfs(graph, visited, x, y):
"""
四个方向: 如果值 <= graph(x,j),则继续搜索
如果有一个值到达第一边界 则 flag = True
如果一个值到达第二边界 则 flag2 = True
"""
if visited[x][y]: return
visited[x][y] = True
dir = [(0, 1), (0, -1), (-1, 0), (1, 0)]
# 遍历是个方向,收集结果,递归,回溯
for i in range(4):
nextx = x + dir[i][0]
nexty = y + dir[i][1]
if nextx < 0 or nexty < 0 or nextx >= len(graph) or nexty >= len(graph[0]): continue # 不满足条件
if graph[nextx][nexty] < graph[x][y]: continue # 可以流过改点
dfs(graph, visited, nextx, nexty) # visited被标记表示下一次不会在搜索它, 说明已经实现了遍历完的功能 而面积,就是在上一个的基础上叠加,所以不需要回溯
def main():
n, m = [int(v) for v in input().split(' ')]
graph = []
visited1 = [[False for _ in range(m)] for _ in range(n)]
visited2 = [[False for _ in range(m)] for _ in range(n)]
n1 = n
while n1:
n1 -= 1
v = [int(v) for v in input().split(' ')]
graph.append(v)
# 最上面、最下面 逆流而上
for j in range(m):
dfs(graph, visited1, 0, j) # 上面
dfs(graph, visited2, n-1, j) # 下面
# 最左面、最右面 逆流而上
for i in range(n):
dfs(graph,visited1, i, 0) # 左面
dfs(graph, visited2, i, m-1) # 右面
for i in range(n):
for j in range(m):
if visited1[i][j] and visited2[i][j]:
print(i, end=' ')
print(j)
main()
104.建造最大岛屿
卡码网题目链接(ACM模式)(opens new window)
题目描述:
给定一个由 1(陆地)和 0(水)组成的矩阵,你最多可以将矩阵中的一格水变为一块陆地,在执行了此操作之后,矩阵中最大的岛屿面积是多少。
岛屿面积的计算方式为组成岛屿的陆地的总数。岛屿是被水包围,并且通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设矩阵外均被水包围。
输入描述:
第一行包含两个整数 N, M,表示矩阵的行数和列数。之后 N 行,每行包含 M 个数字,数字为 1 或者 0,表示岛屿的单元格。
输出描述:
输出一个整数,表示最大的岛屿面积。如果矩阵中不存在岛屿,则输出 0。
输入示例:
4 5
1 1 0 0 0
1 1 0 0 0
0 0 1 0 0
0 0 0 1 1
输出示例 6
提示信息
对于上面的案例,有两个位置可将 0 变成 1,使得岛屿的面积最大,即 6。
数据范围:
1 <= M, N <= 50。
思路
本题的一个暴力想法,应该是遍历地图尝试 将每一个 0 改成1,然后去搜索地图中的最大的岛屿面积。
计算地图的最大面积:遍历地图 + 深搜岛屿,时间复杂度为 n * n。
(其实使用深搜还是广搜都是可以的,其目的就是遍历岛屿做一个标记,相当于染色,那么使用哪个遍历方式都行,以下我用深搜来讲解)
每改变一个0的方格,都需要重新计算一个地图的最大面积,所以 整体时间复杂度为:n^4。
优化思路
其实每次深搜遍历计算最大岛屿面积,我们都做了很多重复的工作。
只要用一次深搜把每个岛屿的面积记录下来就好。
第一步:一次遍历地图,得出各个岛屿的面积,并做编号记录。可以使用map记录,key为岛屿编号,value为岛屿面积
第二步:再遍历地图,遍历0的方格(因为要将0变成1),并统计该1(由0变成的1)周边岛屿面积,将其相邻面积相加在一起,遍历所有 0 之后,就可以得出 选一个0变成1 之后的最大面积。
拿如下地图的岛屿情况来举例: (1为陆地)
0: 面积0
1: 面积1
2: 面积2
3: 面积3
4: 面积4
......
遍历 0 的 方格, 记录其四周的值 , 使用字典映射:总面积 = map[左] + map[右] + map[上] + map[下]
- 字符串接龙
卡码网题目链接(ACM模式)(opens new window)
题目描述
字典 strList 中从字符串 beginStr 和 endStr 的转换序列是一个按下述规格形成的序列:
序列中第一个字符串是 beginStr。
序列中最后一个字符串是 endStr。
每次转换只能改变一个字符。
转换过程中的中间字符串必须是字典 strList 中的字符串。
给你两个字符串 beginStr 和 endStr 和一个字典 strList,找到从 beginStr 到 endStr 的最短转换序列中的字符串数目。如果不存在这样的转换序列,返回 0。
输入描述
第一行包含一个整数 N,表示字典 strList 中的字符串数量。 第二行包含两个字符串,用空格隔开,分别代表 beginStr 和 endStr。 后续 N 行,每行一个字符串,代表 strList 中的字符串。
输出描述
输出一个整数,代表从 beginStr 转换到 endStr 需要的最短转换序列中的字符串数量。如果不存在这样的转换序列,则输出 0。
输入示例
6
abc def
efc
dbc
ebc
dec
dfc
yhn
输出示例
4
提示信息
从 startStr 到 endStr,在 strList 中最短的路径为 abc -> dbc -> dec -> def,所以输出结果为 4
数据范围:
2 <= N <= 500
105.有向图的完全可达性
卡码网题目链接(ACM模式)(opens new window)
【题目描述】
给定一个有向图,包含 N 个节点,节点编号分别为 1,2,…,N。现从 1 号节点开始,如果可以从 1 号节点的边可以到达任何节点,则输出 1,否则输出 -1。
【输入描述】
第一行包含两个正整数,表示节点数量 N 和边的数量 K。 后续 K 行,每行两个正整数 s 和 t,表示从 s 节点有一条边单向连接到 t 节点。
【输出描述】
如果可以从 1 号节点的边可以到达任何节点,则输出 1,否则输出 -1。
【输入示例】
4 4
1 2
2 1
1 3
3 4
【输出示例】
1
【提示信息】
从 1 号节点可以到达任意节点,输出 1。
数据范围:
1 <= N <= 100;
1 <= K <= 2000。
#思路
- 岛屿的周长
卡码网题目链接(ACM模式)(opens new window)
题目描述
给定一个由 1(陆地)和 0(水)组成的矩阵,岛屿是被水包围,并且通过水平方向或垂直方向上相邻的陆地连接而成的。
你可以假设矩阵外均被水包围。在矩阵中恰好拥有一个岛屿,假设组成岛屿的陆地边长都为 1,请计算岛屿的周长。岛屿内部没有水域。
输入描述
第一行包含两个整数 N, M,表示矩阵的行数和列数。之后 N 行,每行包含 M 个数字,数字为 1 或者 0,表示岛屿的单元格。
输出描述
输出一个整数,表示岛屿的周长。
输入示例
5 5
0 0 0 0 0
0 1 0 1 0
0 1 1 1 0
0 1 1 1 0
0 0 0 0 0
输出示例
14
提示信息
岛屿的周长为 14。
数据范围:
1 <= M, N <= 50。
#思路