#375. 山峰与山谷

题目描述

给定一个 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太慢了,会超时。

超时也就超几毫秒。纯属卡常。可别忘了改啊!

点个赞吧!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值