题目描述
在二维地图上, 0代表海洋, 1代表陆地,我们最多只能将一格 0 海洋变成 1变成陆地。进行填海之后,地图上最大的岛屿面积是多少?(上、下、左、右四个方向相连的 1 可形成岛屿)
输入描述
第一行输入两个整数n m(1 <= n,m <= 500 ),代表grid的高和长,
接下来的n行输入m个整数,代表岛屿或者水域
输出描述
输出一行一个整数,代表最大人工岛的面积。
样例
输入
2 2 1 0 0 1
输出
3
这个题简单分为3部分
1.时间 空间
2.搜索 dfs
3.填海 去重 计算
(1)首题数据量看似只有500 但实际很大 搜索首先要500*500
500*500*4+500*500这是已知的 大约在10^6还没爆 但是还要变陆地等其他的
500*500*4*500*500
这不用算就爆了,所以我们可以换一种方法 这个现在会细说
(2)搜索比较好写 但注意的有一点 这个开始(通俗传参)是要符合条件 并且要放在循环里dfs
不能在外面bfs(1,1),因为有的可能不能一次就搜索完 而是要搜索多次 会后多块陆地
具体如下图(0为海洋 1为陆地)
这样一次就不行 并且if判断(a[i][j]==1&&vis[i][j]==0)是陆地 并且没走过才进行传参
dfs有个temp变量 留到(3)再说
方向数组自然就不用多说了
(3)最重要的一部分
依旧还是这个图 这个题想求的是填哪一个海 得到的陆地面积最大
所以肯定会有计算 我们可以列出一个公式
面积S=上+下+左+右+1,1是他本身
我们可以用cnt来标记陆地
这样 用一个cnt标记 海洋自身+1片地+2片地
cnt初始为1 毕竟肯定会有一块陆地
上面提到的temp是用来加的地 就是当前cnt这片地有几块地
temp++;
num[cnt]=temp;
所以这样就很明显了,求出各个区块的面积 最后循环相加 找出最大的即可
但是这是又出现了一个问题
如下图
我想要求出面积 但是按这个图来说 面积必会重复加
所以就要考虑去重 这里我们采用桶 来进行标记 桶很适配这个题
我们设置sum来相加 遍历比大小 maxx和sum
和dfs差不多 最后输出maxx就行了
别忘给flag memset
AC代码如下:
#include<iostream>
#include<cstring>
using namespace std;
int vis[505][505],n,m,a[505][505];
int num[130000],cnt=1;//存储第cnt块面积
int dx[]={1,-1,0,0},dy[]={0,0,1,-1};
int maxx,temp;
int flag[130000];//桶标记出现 重复出现的陆地
void dfs(int x,int y){
vis[x][y]=cnt;
temp++;
for(int i=0;i<4;i++){
int nx=dx[i]+x,ny=dy[i]+y;
if(nx>=1&&nx<=n&&ny>=1&&ny<=m){
if(vis[nx][ny]==0&&a[nx][ny]==1){
//cout<<1; 只是测试进没进循环 没任何含义
dfs(nx,ny);
}
}
}
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>a[i][j];
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(a[i][j]==1&&vis[i][j]==0){
temp=0;
dfs(i,j);
num[cnt]=temp;
cnt++;
}
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(a[i][j]==0){
memset(flag,0,sizeof(flag));
int sum=1;
for(int k=0;k<4;k++){
int nx=i+dx[k],ny=j+dy[k];
if(nx>=1&&nx<=n&&ny>=1&&ny<=m){
if(a[nx][ny]==1&&flag[vis[nx][ny]]==0){
sum+=num[vis[nx][ny]];
flag[vis[nx][ny]]++;
}
}
}
maxx=max(maxx,sum);
}
}
}
cout<<maxx;
return 0;
}