hiho一下 第156周 岛屿
2017-07-05 22:41
429 查看
题意
给你一张某一海域卫星照片,你需要统计:1. 照片中海岛的数目
2. 照片中面积不同的海岛数目
3. 照片中形状不同的海岛数目
其中海域的照片如下,”.”表示海洋,”#”表示陆地。在”上下左右”四个方向上连在一起的一片陆地组成一座岛屿。
.####.. .....#. ####.#. .....#. ..##.#.
上图所示的照片中一共有4座岛屿;其中3座面积为4,一座面积为2,所以不同面积的岛屿数目是2;有两座形状都是”####”,所以形状不同的岛屿数目为3。
解题思路
这道题需要我们求出三个数值,一是海岛数目,二是面积不同的海岛数目,三是形状不同的海岛数目。第一个小问题是最基本的搜索问题。一般我们可以从上到下、从左到右扫描,直到发现一个没有处理过的’#’。然后从这个’#’开始沿着4个方向扩展,把连在一起的’#’都找出来。这些连在一起的’#’就组成一个岛屿。
第二个小问题很容易就可以在第一个小问题的基础上求得。我们只需在dfs/bfs找岛屿的过程中保存一下’#’的数目即可。
第三个小问题判断形状相同,我们可以用相对位置来判断。
以样例数据为例,第一行的”####”对应的坐标(行从上到下,列从左到右)依次是(0, 1)(0, 2)(0, 3)(0, 4)。如果我们以其先最上其次最左的点,也就是(0, 1)为基准的话,相对位置序列是(0, 0)(0, 1)(0, 2)(0, 3)。
同理第三行的”####”的坐标依次是(2, 0)(2, 1)(2, 2)(2, 3),其相对位置也是(0, 0)(0, 1)(0, 2)(0, 3)。两个岛屿形状相同,当且仅当它们的相对位置序列完全相同。
所以我们需要在dfs/bfs找岛屿的过程中把陆地的位置都保存下来。
以样例为例,处理过程为:
输入:
5 7 .####.. .....#. ####.#. .....#. ..##.#.
DFS搜索,用一个二维数组记录岛屿:
0111100 0000020 3333020 0000020 0044020
在搜索时,用一个结构体记录每个岛屿的位置:
1 (0,1)(0,2)(0,3)(0,4) 2 (1,5)(2,5)(3,5)(4,5) 3 (2,0)(2,1)(2,2)(2,3) 4 (4,2)(4,3)
转换相对位置:
1 (0,0)(0,1)(0,2)(0,3) 2 (0,0)(1,0)(2,0)(3,0) 3 (0,0)(0,1)(0,2)(0,3) 4 (0,0)(0,1)
输出结果:
4 2 3
参考代码
#include <bits/stdc++.h> using namespace std; #define MAXN 51 char M[MAXN][MAXN]; int visited[MAXN][MAXN]; bool used[MAXN*MAXN]; int dx[4]={-1,0,1,0}; int dy[4]={0,1,0,-1}; int n,m; struct Node{ int k; int x[MAXN*MAXN],y[MAXN*MAXN]; }P[MAXN*MAXN]; bool check(int x,int y){ if (!visited[x][y] && 0<=x && x<n && 0<=y && y<m && M[x][y]=='#') return 1; return 0; } void DFS(int x,int y,int cnt){ visited[x][y]=cnt; P[cnt].x[P[cnt].k]=x; P[cnt].y[P[cnt].k]=y; P[cnt].k++; for (int i=0;i<4;i++){ int x2=x+dx[i]; int y2=y+dy[i]; if (check(x2,y2)) DFS(x2,y2,cnt); } } int main(){ while (cin>>n>>m){ for (int i=0;i<n;i++) cin>>M[i]; memset(visited,0,sizeof(visited)); for (int i=0;i<MAXN*MAXN;i++) P[i].k=0; int cnt=1; for (int i=0;i<n;i++){ for (int j=0;j<m;j++){ if (!visited[i][j] && M[i][j]=='#'){ DFS(i,j,cnt++); } } } /* for (int i=0;i<n;i++){ for (int j=0;j<m;j++) cout<<visited[i][j]; cout<<endl; } for (int i=1;i<cnt;i++){ cout<<i<<" "; for (int j=0;j<P[i].k;j++) cout<<"("<<P[i].x[j]<<","<<P[i].y[j]<<")"; cout<<endl; } */ for (int i=1;i<cnt;i++){ for (int j=1;j<P[i].k;j++){ P[i].x[j]-=P[i].x[0]; P[i].y[j]-=P[i].y[0]; } P[i].x[0]=P[i].y[0]=0; } /* for (int i=1;i<cnt;i++){ cout<<i<<" "; for (int j=0;j<P[i].k;j++) cout<<"("<<P[i].x[j]<<","<<P[i].y[j]<<")"; cout<<endl; } */ int cnt2=0; memset(used,0,sizeof(used)); for (int i=1;i<cnt;i++){ if (used[i]) continue; cnt2++; for (int j=i+1;j<cnt;j++) if (P[i].k==P[j].k) used[j]=1; } //cout<<cnt2<<endl; int cnt3=0; memset(used,0,sizeof(used)); for (int i=1;i<cnt;i++){ if (used[i]) continue; cnt3++; for (int j=i+1;j<cnt;j++){ if (P[i].k!=P[j].k) continue; bool flag=0; for (int t=0;t<P[i].k;t++){ if (P[i].x[t]!=P[j].x[t] || P[i].y[t]!=P[j].y[t]){ flag=1; break; } } if (!flag) used[j]=1; } } //cout<<cnt3<<endl; cout<<cnt-1<<" "<<cnt2<<" "<<cnt3<<endl; } return 0; }
相关文章推荐
- hiho一下 第156周 岛屿
- hiho一下 第156周 岛屿 (dfs)
- hiho一下[156周]:岛屿
- hiho一下 第123周 后缀数组四·重复旋律4
- hiho一下 第125周 GeoHash一·编码解码
- hiho一下 第二十一周(线段树 离散化)
- hiho一下 第117周 #1393 : 网络流三·二分图多重匹配 【网络流--增加源点-汇点 Ford-Fulkerson算法】
- (hiho一下第三周)#1015 KMP算法 【模版】
- hiho一下 37 (无序二分·k小数)
- hiho一下 第四十五周 博弈游戏·Nim游戏·二(转成NIm)
- hiho一下 第四十八周题目1 : 拓扑排序·二
- hiho一下 第五十四周 题目1 : 连通性·三
- hiho一下 第161周 树结构判定 题解
- hiho一下,第163周 题目1 : 希尔伯特曲线
- hiho一下 第六十四周 Right-click Context Menu
- hiho一下 第六十六周
- hiho一下 第158周/1318 : 非法二进制数
- 分隔相同字符 hiho一下第165周
- hiho一下 第175周 Robots Crossing River
- hiho一下 第九十三周 数论二·Eular质数筛法