山峰和山谷【深度优先搜索】

山峰和山谷

题目描述

F G D FGD FGD小朋友特别喜欢爬山,在爬山的时候他就在研究山峰和山谷。
为了能够对旅程有一个安排,他想知道山峰和山谷的数量。
给定一个地图,为 F G D FGD FGD想要旅行的区域,地图被分为 n × n n×n n×n 的网格,每个格子 ( i , j ) (i,j) (i,j)的高度 w ( i , j ) w(i,j) w(i,j)是给定的。
若两个格子有公共顶点,那么它们就是相邻的格子,如与 ( i , j ) (i,j) (i,j)相邻的格子有 ( i − 1 , j − 1 ) (i−1,j−1) (i1,j1), ( i − 1 , j ) (i−1,j) (i1,j), ( i − 1 , j + 1 ) (i−1,j+1) (i1,j+1), ( i , j − 1 ) (i,j−1) (i,j1), ( i , j + 1 ) (i,j+1) (i,j+1), ( i + 1 , j − 1 ) (i+1,j−1) (i+1,j1), ( i + 1 , j ) (i+1,j) (i+1,j), ( i + 1 , j + 1 ) (i+1,j+1) (i+1,j+1)
你的任务是,对于给定的地图,求出山峰和山谷的数量,如果所有格子都有相同的高度,那么整个地图即是山峰,又是山谷。
山峰定义为:一个连通块,对于每一个属于此连通块的点,有:这个点周围所有与它八连通的点值都比这个点的值要
山谷定义为:一个连通块,对于每一个属于此连通块的点,有:这个点周围所有与它八连通的点值都比这个点的值要

输入描述

第一行包含一个正整数 n n n,表示地图的大小 ( 1 < = n < = 1000 ) (1<=n<=1000) 1<=n<=1000
接下来一个 n × n n×n n×n 的矩阵,表示地图上每个格子的高度 w ( 0 < = w < = 1000000000 ) w(0<=w<=1000000000) w0<=w<=1000000000

输出描述

共一行,包含两个整数,表示山峰和山谷的数量。

样例

输入

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

提示

样例图片

思路

这个题乍一看并不太难,无非就是方向数组遍历八个方向深搜
但细看可能就有人被难住了:怎么找连通块外加遍历它外包的点来确定是山峰还是山谷呢?
那就要引入正题了——两个标记数 f l a g 1 flag1 flag1 f l a g 2 flag2 flag2
只要我们在遍历周围点时,周围数比当前数,就让 f l a g 1 = 1 flag1=1 flag1=1(即山谷),反之如果就让 f l a g 2 = 1 flag2=1 flag2=1(即山峰),如果相等就说明是连通块就从新点开始搜索即可
值得注意的是(我原来错的地方(・ω・`ll)),在判断当前点是否被访问过跳出时,要先把 f l a g 1 flag1 flag1 f l a g 2 flag2 flag2判断完,不然会少找一些点
最后注意一下数组清空 f l a g flag flag清空之类的问题这个题就没有任何问题了

AC代码

#include<iostream>
#include<cstdio>

using namespace std;

int n;

int ans1 = 0, ans2 = 0; //山峰山谷计数器
bool flag1 = 0, flag2 = 0; //山峰山谷标记变量
//方向数组
int dx[] = {0, 1, 0, -1, -1, -1, 1, 1};
int dy[] = {1, 0, -1, 0, -1, 1, -1, 1};
int a[1005][1005];
bool vis[1005][1005];
void dfs(int x, int y) {
	for (int i = 0; i < 8; i++) {
		int nx = x + dx[i], ny = y + dy[i];
		if (nx < 0 || ny < 0 || nx >= n || ny >= n) {
			continue;
		}
		//可能是山谷
		if (a[nx][ny] > a[x][y]) {
			flag1 = 1;
		}
		//可能是山峰
		if (a[nx][ny] < a[x][y]) {
			flag2 = 1;
		}
		//如果走过就跳掉
		if (vis[nx][ny]) {
			continue;
		}
		//从新点开始搜索
		if (a[nx][ny] == a[x][y]) {
			vis[nx][ny] = 1;
			dfs(nx, ny);
		}
	}
}

int main() {
	scanf("%d", &n);
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			scanf("%d", &a[i][j]);
		}
	}
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			if (!vis[i][j]) {
				//记得把标记数清空1
				flag1 = 0;
				flag2 = 0;
				vis[i][j] = 1;
				dfs(i, j);
				//是山谷
				if (flag1 == 1 && flag2 == 0) {
					ans1++;
				}
				//是山峰
				if (flag1 == 0 && flag2 == 1) {
					ans2++;
				}
				//如题,整张图一样高,既是山峰又是山谷
				if (flag1 == 0 && flag2 == 0) {
					ans1++;
					ans2++;
				}
			}
		}
	}
	printf("%d %d", ans2, ans1);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值