题目描述
给定一个 n×n 的网格状地图,每个方格 (i,j)有一个高度 wij 。如果两个方格有公共顶点,则它们是相邻的。
定义山峰和山谷如下:
均由地图上的一个连通块组成;
所有方格高度都相同;
周围的方格(即不属于山峰或山谷但与山峰或山谷相邻的格子)高度均大于山谷的高度,或小于山峰的高度。
求地图内山峰和山谷的数量。特别地,如果整个地图方格的高度均相同,则整个地图既是一个山谷,也是一个山峰。
输入格式
第一行一个整数n(2≤n≤1000),表示地图的大小。
接下来 n 行每行 n 个整数表示地图。第 i 行有 n 个整数 wij,wij,…,wij(0≤wij≤1000000000),表示地图第 i 行格子的高度。
输出格式
输出一行两个整数,分别表示山峰和山谷的数量。
样例
输入样例 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
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 3 4 5 6 7
2 8 8 8 8 8 6
3 8 8 8 8 8 5
4 8 8 8 8 8 4
5 8 8 8 8 8 3
6 8 8 8 8 8 2
7 6 5 4 3 2 1
例子中值为8的连通块外围的数字都小于8,所以可以判断它是山峰。
啥是山谷?
山谷的定义是:一个连通块周围的方块内的数字都比它大,如这样一个例子:
2 3 4 5 6
3 1 1 1 5
4 1 1 1 4
5 1 1 1 3
6 5 4 3 2
例子中值为1的连通块外围的数字都大于1,所以可以判断他是山谷。
啥也不是?
如果一个连通块的外围有的数字比它的值要大,有的数字比它的值要小,那这个连通块就啥也不是。例子:
1 2 3 4 5
2 3 3 3 4
3 3 3 3 3
4 3 3 3 2
5 4 3 2 1
广搜的实现
理清了山峰与山谷的定义,我们就可以写广搜了。步骤如下:
寻找一个连通块
如果当前判断的点大于连通块的值,标记。
如果当前判断的点小于连通块的值,标记。
如果当前判断的点等于连通块的值,入队,等待下一次搜索。
当广搜搜索完后,我们就要对相应的计数器进行操作了。
如果标记山峰的变量与标记山谷的变量都为false,说明当前的地图是特殊情况,即整个地图的值都一样,那么山峰与山谷的计数器都加一。
如果标记山峰的变量为true,标记山谷的变量为false,山峰的计数器加一。
如果标记山峰的变量为false,标记山谷的变量为true,山谷的计数器加一。
如果标记山峰的变量与标记山谷的变量都为true,说明这个连通块啥也不是,计数器不变。
广搜代码实现
void bfs(int x,int y)
{
bool g,f;
g=f=false;
queue<id>q;
q.push(id{x,y});
vis[x][y]=1;
while(!q.empty())
{
id t=q.front();
q.pop();
for(int i=0;i<8;i++)
{
int nx=t.x+xx[i];
int ny=t.y+yy[i];
if(pd(nx,ny)&&(!vis[nx][ny]||a[x][y]!=a[nx][ny]))
{
if(a[nx][ny]>a[x][y])g=true;
if(a[nx][ny]<a[x][y])f=true;
if(a[nx][ny]==a[x][y])
{
q.push(id{nx,ny});
vis[nx][ny]=1;
}
}
}
}
if(!g&&!f)gg++,ff++;
if(!g&&f)ff++;
if(g&&!f)gg++;
}
AC代码实现
#include<bits/stdc++.h>
using namespace std;
int n,gg,ff;//地图边长,计数器
int a[1005][1005];//地图
bool vis[1005][1005];//标记数组
struct id
{
int x,y;
};
int xx[]={-1,0,1,0,-1,-1,1,1};//位置偏移数组
int yy[]={0,1,0,-1,-1,1,-1,1};//位置偏移数组
bool pd(int x,int y)//判断是否越界
{
return x>0&&y>0&&x<=n&&y<=n;
}
void bfs(int x,int y)//广搜
{
bool g,f;
g=f=false;
queue<id>q;
q.push(id{x,y});
vis[x][y]=1;
while(!q.empty())
{
id t=q.front();
q.pop();
for(int i=0;i<8;i++)
{
int nx=t.x+xx[i];
int ny=t.y+yy[i];
if(pd(nx,ny)&&(!vis[nx][ny]||a[x][y]!=a[nx][ny]))//判断周围
{
if(a[nx][ny]>a[x][y])g=true;
if(a[nx][ny]<a[x][y])f=true;
if(a[nx][ny]==a[x][y])
{
q.push(id{nx,ny});
vis[nx][ny]=1;
}
}
}
}
if(!g&&!f)gg++,ff++;//计数器的相应操作
if(!g&&f)ff++;
if(g&&!f)gg++;
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
scanf("%d",&a[i][j]);
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(!vis[i][j])
{
bfs(i,j);
}
}
}
printf("%d %d",ff,gg);
return 0;
}
后记
由于数据会比较大,所以广搜勉强能过,但是注意主函数里面的输入输出都改成C语言的才行,因为cin和cout太慢了,会超时。
超时也就超几毫秒。纯属卡常。可别忘了改啊!
点个赞吧!