【题目描述】
给定一个n×n的网格状地图,每个方格(i,j)有一个高度 wij 。如果两个方格有公共顶点,则它们是相邻的。
定义山峰和山谷如下:
均由地图上的一个连通块组成;
所有方格高度都相同;
周围的方格(即不属于山峰或山谷但与山峰或山谷相邻的格子)高度均大于山谷的高度,或小于山峰的高度。
求地图内山峰和山谷的数量。特别地,如果整个地图方格的高度均相同,则整个地图既是一个山谷,也是一个山峰。
特别注意:如果一个联通块既属于山峰,也属于山谷(即相邻联通块既有比自身高的,也有比自身矮的),那么该联通块属于半山腰,即不算山峰,也不算山谷,如样例2。
【输入】
第一行一个整数n(2≤n≤1000),表示地图的大小。
接下来 n 行每行 n 个整数表示地图。第 i 行有 n个整数 wi1, wi2, ..., win,(0≤wi1≤50),表示地图第 i 行格子的高度。
【输出】
输出一行两个整数,分别表示山峰和山谷的数量。
样例 #1
样例输入 #1
5
8 8 8 7 7
7 7 8 8 7
7 7 7 7 7
7 8 8 7 8
7 8 8 8 8
样例输出 #1
2 1
样例 #2
样例输入 #2
5
5 7 8 3 1
5 5 7 6 6
6 6 6 2 8
5 7 2 5 8
7 1 0 1 7
样例输出 #2
3 3
提示与说明
样例 1 解释:
样例 2 解释:
大体思路
题目让我们判断山峰和山谷,如果想样例1的话,这并不难。但是,问题出在样例2,有一个半山腰的概念(即既是山峰又是山谷)。
我们可以设立两个变量,分别表示山峰和山谷的状态,在每次dfs时判断并刷新山峰和山谷的状态,排除既是山峰又是山谷(半山腰)的情况。
代码如下
#include "bits/stdc++.h"
using namespace std;
const int N = 1e3+8;
int n, a[N][N], sf, sg;
bool vis[N][N], f, g;//用vis数组来表示每个格子是否已走过,f和g表示每个格子山峰和山谷的状态
int xx[9] = {0,-1,-1,-1,0,1,1,1,0}, yy[9] = {0,-1,0,1,1,1,0,-1,-1};
void dfs(int x, int y) {
for(int i=1; i<=8; i++) {//深搜核心步骤
int dx = x + xx[i],dy = y + yy[i];
if(dx < 1 || dx > n || dy < 1 || dy > n) continue;//判断是否越界
if(a[dx][dy] == a[x][y]) {
if(vis[dx][dy] == true) continue;//判断格子是否被走过
vis[dx][dy] = true;
dfs(dx,dy);
}else{
if(a[dx][dy] > a[x][y]) g=1;//判断山谷状态
if(a[dx][dy] < a[x][y]) f=1;//判断山峰状态
}
}
}
int main() {
cin>>n;
for(int i=1; i<=n; i++) {
for(int j=1; j<=n; j++) {
cin>>a[i][j];
}
}
for(int i=1; i<=n; i++) {
for(int j=1; j<=n; j++) {
if(vis[i][j] == false) {
vis[i][j] = true;
g=0, f=0;//刷新山峰和山谷状态
dfs(i,j);
if(g == 1 && f == 1) continue;
if(g == 0 && f == 1) sf++;//刷新山峰数
else if(g == 1 && f == 0) sg++;//刷新山谷数
else if(g == 0 && f == 0){
cout<<"1 1"<<endl;
return 0;
}
}
}
}
cout<<sf<<' '<<sg<<endl;//输出
return 0;
}