代码:(bfs广搜)
- #include
- #include
- #include
- using namespace std;
- int dir[4][2] = {1,0,0,1,-1,0,0,-1};
- int count;
- void bfs(vector
int >>&grid,int x,int y){ - queue
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
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 深搜)
- #include
- #include
- #include
- using namespace std;
- int dir[4][2] = {1,0,0,1,-1,0,0,-1};
- int count;
- void bfs(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
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;
- }
思路:我的博客快做成个人错误大赏了。。。
这次的错误是 在进行下标是否非法的判断的时候,我又写错了。一定要注意边界条件啊,以后检查的时候就应该找这种判断语句好好看看。
代码:(深搜dfs)
- #include
- #include
- #include
- using namespace std;
- int dir[4][2] = {1,0,0,1,-1,0,0,-1};
- int count;
- void bfs(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
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
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,输出就好了
代码: (深搜dfs)
- #include
- #include
- using namespace std;
- int dir[4][2] = {0,1,1,0,0,-1,-1,0};
- void dfs(const vector
int >> &grid,vectorbool >> &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
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
bool>> firstBorder(n,vector<bool>(m,false)); - 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;了。
代码:
- #include
- #include
- #include
- #include
- using namespace std;
- int count;
- int dir[4][2] = {0,1,1,0,0,-1,-1,0};
- void dfs(vector
int >>&grid,vectorbool >>&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
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
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;
- }
思路:这道题是先计算各个岛屿的面积,然后遍历每一块海域,将这块添加的单元与其临近的岛屿面积进行相加求和,保存里面的最大值。
这道题真的是错死我了。。。这个涉及到很多细节,比如要考虑全是陆地的情况,要将每个岛屿进行面积和标号的映射,要在计算连接后的总面积的时候,将统计过的岛屿进行标记。。。我真的,太痛了。