山峰与山谷(dfs)

#2653. 「POI2007」山峰和山谷 Ridges and Valleys
传统1000 ms32 MiB
654
通过
1992
提交
题目描述
译自 POI 2007 Stage 2. Day 0「Ridges and Valleys」

给定一个 n \times n 的网格状地图,每个方格 (i,j) 有一个高度 w_{ij}。如果两个方格有公共顶点,则它们是相邻的。

定义山峰和山谷如下:

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

输入格式
第一行一个整数 n (2 \le n \le 1000),表示地图的大小。

接下来 n 行每行 n 个整数表示地图。第 i 行有 n 个整数 w_{i1}, w_{i2}, \ldots, w_{in} (0 \le w_{ij} \le 1\ 000\ 000\ 000),表示地图第 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
输出
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
输出
3 3

整体思路

数据输入时先判断一下是不是有一个值组成的地图,然后以每个点作为根节点找连通块并判断这是山峰还是山谷,找过的连通块用vis数组记录,用ans储存山峰和山谷的数量

ac代码

#include
using namespace std;
int n,mp[1050][1050],ans1=0,ans2=0,bd;//n表示的是图的边长大小,mp数组用于输入图的样子,
//ans1表示的是山谷的数量,ans2表述的是山峰的数量,bd用于判断这是山峰还是山谷
bool vis[1050][1050];//vis数组用于记录这个图上的格子有没有已经使用过,即和之前的格子已经形成连通块
inline bool check(int x,int y){
	if (x>=1 and y<=n and x<=n and y>=1)
		return 1;
	return 0;
}//用于判断有没有越界
void dfs(int x,int y,int q){
	for (int i=-1;i<=1;i++)
		for (int j=-1;j<=1;j++){//ij代替了之前的方向数组
			if (i==0 and j==0) continue;//移动00等于没动,跳过
			int xx=i+x,yy=j+y;
			if (!check(xx,yy)) continue;//如果这样移动越界,跳过
			if (q==mp[xx][yy] and vis[xx][yy]==0)//如果移动后的值和根节点的格子相等并且没有访问过
				vis[xx][yy]=1,dfs(xx,yy,q);//访问这个格子,然后从这个格子接着向下递归
			else if (mp[xx][yy]<q and bd==1)//如果已经判断过之前其他的格子断定是山谷,
			//但是遍历到这里周围的值又小于此格子,即不是山峰也不是山谷,改变bd
				bd=-1;
			else if (mp[xx][yy]>q and bd==2)//如果已经判断过之前其他的格子断定是山峰,
			//但是遍历到这里周围的值又大于此格子,即不是山峰也不是山谷,改变bd
				bd=-1;
			else if (bd==0){//如果还没有判断周围是山峰还是山谷
				if (mp[xx][yy]<q) bd=2;//周围的值小于此格子,证明格子所处的位置是山峰
				if (mp[xx][yy]>q) bd=1;//周围的值大于此格子,证明格子所处的位置是山谷
			}
		}
	return;
}
int main(){
	cin>>n;
	int tmp=1,pd;
	for (int i=1;i<=n;i++)
		for (int j=1;j<=n;j++){
			cin>>mp[i][j];//输入地图
			if (i==1 and j==1) {pd=mp[i][j];continue;}//取地图的第一个值
			if (mp[i][j]!=pd) tmp=0;//用于判断之格图是不是有一个值组成的
		}
			
	if (tmp){cout<<"1 1";return 0;}//如果整个图是有一个值组成的,就输出1 1
	for (int i=1;i<=n;i++){
		for (int j=1;j<=n;j++){
			if (vis[i][j]) continue;//如果已经访问过的话直接跳过就可以
			bd=0;vis[i][j]=1;//初始化bd,访问这个值
			dfs(i,j,mp[i][j]);//搜索位于i行j列的值mp[i][j]
			if (bd==1) ans1++;//如果是山谷,山谷的总数+1
			if (bd==2) ans2++;//如果是山峰,山峰的总数+1
		}
	}
	cout<<ans2<<' '<<ans1;//输出山峰和山谷的数量
	return 0;
}

你可能感兴趣的:(深度优先,算法,图论)