【YBT高效进阶】1基础算法/5广度优先搜索/2山峰和山谷

【YBT高效进阶】1基础算法/5广度优先搜索/2山峰和山谷

内存限制:256 MiB
时间限制:1000 ms
标准输入输出
题目类型:传统
评测方式:文本比较

题目描述

给定一个N*N 的网格状地图,每个方格(i,j)有一个高度 w(i,j) 。如果两个方格有公共顶点,则它们是相邻的。

定义山峰山谷如下:

均由地图上的一个联通块组成。
所有方格高度都相同。
周围的方格(即不属于山峰或山谷但与山峰或山谷相邻的格子)高度均大于山谷的高度,或小于山峰的高度。
求地图内山峰和山谷的数量。特别的,如果整个地图方格的高度均相同,则整个地图即是一个山谷,也是一个山峰。

注:有与 (x,y) 有公共顶点的点集是 (x,y) 的八连通。

输入格式

第一行一个正整数 n,表示地图的大小。

接下来 n 行,每行 n 个整数表示地图。第 i 行有 n 个正整数 w[i][1],w[i][2]……w[i][n],表示地图第 i 行格子的高度。

输出格式

输出一行两个整数,分别表示山峰和山谷的数量。

样例

样例输入

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

样例输出

2 1

数据范围与提示

对于 100% 的数据,有 2<=n<=1000,0<=w[i][j]<=109

思路

每个格子如果没有走过就用BFS搜一次。
计算出当前连通块周围是否有点小于当前连通块,周围是否有点大于当前连通块。
有点小于当前连通块,没有点大于当前连通块:山峰。
没有点小于当前连通块,有点大于当前连通块:山谷。
没有点小于当前连通块,没有点大于当前连通块:山峰和山谷。

代码

#include<iostream>
#include<cstdio>
#include<cstring> 
using namespace std;
struct jgt
{
	int x,y;
};
jgt b[1000010];
int a[1010][1010];
bool d[1010][1010];
int n,sx,sy,zx,zy,way[8][2]={{-1,-1},{-1,0},{-1,1},{0,-1},{0,1},{1,-1},{1,0},{1,1}};
void input()//输入
{
	int i,j;
	char t;
	memset(d,true,sizeof(d));
	scanf("%d",&n);
	for(i=1;i<=n;i++)
		for(j=1;j<=n;j++)
			scanf("%d",&a[i][j]);
	return;
}
int BFS(int sx,int sy)//BFS搜索
{
	int i,l,r,dx,dy;
	bool f=0,g=0;
	d[sx][sy]=0;
	b[1].x=sx;
	b[1].y=sy;
	for(l=r=1;l<=r;l++)
	{
		for(i=0;i<8;i++)//扩展
		{
			dx=b[l].x+way[i][0];
			dy=b[l].y+way[i][1];
			if(dx>=1&&dy>=1&&dx<=n&&dy<=n)
			{
				f|=(a[dx][dy]<a[b[l].x][b[l].y]);//f=1表示当前连通块周围有点小于当前连通块。
				g|=(a[dx][dy]>a[b[l].x][b[l].y]);//d=1表示当前连通块周围有点大于当前连通块。
				if(d[dx][dy]&&a[dx][dy]==a[b[l].x][b[l].y])
				{
					r++;
					b[r].x=dx;
					b[r].y=dy;
					d[dx][dy]=0;
				}
			}
		}
	}
	if(f&&(!g))//f=1,g=0,山峰
		return 1;
	if((!f)&&g)//f=0,g=1,山谷
		return -1;
	if((!f)&&(!g))//f=0,g=0,是山峰也是山谷
		return 2;
	return 0;
}
int main()
{
	int i,j,t,ansf=0,ansg=0;
	input();
	for(i=1;i<=n;i++)
	{
		for(j=1;j<=n;j++)
		{
			if(d[i][j])
			{
				t=BFS(i,j);
				ansf+=(t==1)||(t==2);//累计
				ansg+=(t==-1)||(t==2);
			}
		}
	}
	printf("%d %d",ansf,ansg);
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值