1.孤岛的总面积
代码:(bfs广搜)
cpp
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
int dir[4][2] = {1,0,0,1,-1,0,0,-1};
int count;
void bfs(vector<vector<int>>&grid,int x,int y){
queue<pair<int,int>> que;
que.push({x,y});
grid[x][y] = 0; // 这里用grid的元素变为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});
grid[nextx][nexty] = 0;
count++;
}
}
}
}
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 = 1; i < n - 1; i++){
for(int j = 1; j < m - 1; j++){
if(grid[i][j] == 1) bfs(grid,i,j);
}
}
// 输出
cout << count << endl;
}
思路:基础题型,这次直接在grid表上进行标记。先把靠近陆地的岛屿都标为0。将用于统计面积的变量的count置为0。接下来就可以排除临近陆地的岛屿,只统计孤岛的数量了。
易错点:我又犯错了。先是忘记写命名空间了,然后又是在if判断里二维数组我只写了一个下标,最后是找边界找错了,我的循环变量i是在变的,我只要固定另一个下标为临界值就好了。不知道为什么我把i放到了边界的运算里(。。脑子糊了)
代码:(dfs 深搜)
cpp
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
int dir[4][2] = {1,0,0,1,-1,0,0,-1};
int count;
void bfs(vector<vector<int>>&grid,int x,int y){
if(grid[x][y] == 0){
return;
}
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;
}
bfs(grid,nextx,nexty);
}
}
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 = 1; i < n - 1; i++){
for(int j = 1; j < m - 1; j++){
if(grid[i][j] == 1) bfs(grid,i,j);
}
}
// 输出
cout << count << endl;
}
思路:我的博客快做成个人错误大赏了。。。
这次的错误是 在进行下标是否非法的判断的时候,我又写错了。一定要注意边界条件啊,以后检查的时候就应该找这种判断语句好好看看。
2.沉没孤岛
代码:(深搜dfs)
cpp
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
int dir[4][2] = {1,0,0,1,-1,0,0,-1};
int count;
void bfs(vector<vector<int>>&grid,int x,int y){
if(grid[x][y] == 2||grid[x][y] == 0){
return;
}
grid[x][y] = 2;
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;
}
bfs(grid,nextx,nexty);
}
}
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];
}
}
// 处理
// 将临近陆地的标为2 和 孤岛区分开
vector<vector<bool>> visited(n,vector<bool>(m,false));
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);
}
// 将孤岛沉没 将临近陆地的单元还原
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
if(grid[i][j] == 1) grid[i][j] = 0;
if(grid[i][j] == 2) grid[i][j] = 1;
}
}
// 输出
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
cout << grid[i][j] << " ";
}
cout << endl;
}
}
思路:这里比较巧妙的就是因为临近陆地的岛屿比较好判断,所以将其标记为2,只要与孤岛区别开就好了。接下来,就是把1变为0,把2变为1,输出就好了
3.水流问题
代码: (深搜dfs)
cpp
#include <iostream>
#include <vector>
using namespace std;
int dir[4][2] = {0,1,1,0,0,-1,-1,0};
void dfs(const vector<vector<int>> &grid,vector<vector<bool>> &visited,int x, int y){
if(visited[x][y]) return;
visited[x][y] = true;
for(int i = 0; i < 4; i++){
int nextx = x + dir[i][0];
int nexty = y + dir[i][4];
if(nextx < 0||nextx >= grid.size()||nexty < 0||nexty >= grid[0].size()){
continue;
}
// 必须从低到高
if(grid[nextx][nexty] < grid[x][y]) continue;
dfs(grid,visited,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];
}
}
// 处理
vector<vector<bool>> firstBorder(n,vector<bool>(m,false));
vector<vector<bool>> secondBorder(n,vector<bool>(m,false));
for(int i = 0; i < n; i++){
dfs(grid,firstBorder,i,0);
dfs(grid,secondBorderBorder,i,m - 1);
}
for(int j = 0; j < m; j++){
dfs(grid,firstBorder,0,j);
dfs(grid,secondBorder,n - 1,j);
}
// 输出
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
if(firstBorder[i][j]&&secondBorder[i][j]){
cout << i << j << endl;
}
}
}
}
思路:这道题的优化很巧妙,因为从边界出发好判断,所以直接从边界出发,把边界可以到达的地方而且是递增的单元进行标记。上边界和下边界各用一套标记,当一个单元被标记两次时,就说明它时满足题意的。
易错点:我自己写了半天,忘记写最重要的 if(grid[nextx][nexty] < grid[x][y]) continue;了。
4.建造最大岛屿
代码:
cpp
#include <iostream>
#include <vector>
#include <unordered_set>
#include <unordered_map>
using namespace std;
int count;
int dir[4][2] = {0,1,1,0,0,-1,-1,0};
void dfs(vector<vector<int>>&grid,vector<vector<bool>>&visited,int x,int y,int mark){
if(visited[x][y]||grid[x][y] == 0) return;
visited[x][y] = true; // 标记已访问
grid[x][y] = mark; // 每个岛屿都有对应的标签
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;
}
dfs(grid,visited,nextx,nexty,mark);
}
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];
}
}
// 处理
vector<vector<bool>> visited(n,vector<bool>(m,false));
unordered_map<int,int> gridNum;
int mark = 2; // 记录岛屿的编号
bool isAllGrid = true; // 记录整个地图是否都是陆地(如果是,就没法添加陆地了)
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
if(grid[i][j] == 0) isAllGrid = false;
if(!visited[i][j] && grid[i][j] == 1){
count = 0;
dfs(grid,visited,i,j,mark);
gridNum[mark] = count; // 记录每一个岛屿的面积
mark++;
}
}
}
if(isAllGrid == true) {
cout << n*m << endl;
return 0;
}
// 根据所填陆地,计算周边岛屿面积之和
int result = 0;
unordered_set<int> visitedGrid; // 标记访问过的岛屿
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
count = 1; // 记录连接后的岛屿数量
visitedGrid.clear();
if(grid[i][j] == 0){
for(int k = 0; k < 4; k++){
int nexti = i + dir[k][0];
int nextj = j + dir[k][1];
if(nexti < 0||nexti >= grid.size()||nextj < 0||nextj >= grid[0].size()){
continue;
}
if(visitedGrid.count(grid[nexti][nextj])) continue; // 添加过的岛屿不要重复添加
count += gridNum[grid[nexti][nextj]];
visitedGrid.insert(grid[nexti][nextj]);
}
}
result = max(result,count);
}
}
cout << result << endl;
}
思路:这道题是先计算各个岛屿的面积,然后遍历每一块海域,将这块添加的单元与其临近的岛屿面积进行相加求和,保存里面的最大值。
这道题真的是错死我了。。。这个涉及到很多细节,比如要考虑全是陆地的情况,要将每个岛屿进行面积和标号的映射,要在计算连接后的总面积的时候,将统计过的岛屿进行标记。。。我真的,太痛了。