[POI2007]GRZ-Ridges and Valleys 题解

(2022-12-28 )

AcWing 1106

洛谷 P3456

题目大意

找出一个图中所有大于(或小于)周围相邻的非连通块点的所有连通块个数。

就是说,对于一个连通块:

如果它周围的点都低于它,那么山峰数量 +1;

如果它周围的点都高于它,那么山谷数量 +1。

做法

直接dfs,不是很喜欢用bfs,感觉bfs写起来还挺麻烦的,而且可玩性没有dfs高。

我们dfs,同时返回一个状态值表示该点所到达的周围非连通块的情况:

1表示所到达点周围的非连通块点都小于连通块高度;

0表示所到达点周围的非连通块点都大于联通块高度;

-1则表示所到达点周围非连通块点高度情况不相同(有高有低)。

dfs的过程种有两种情况:

第一种:连通块点

用一个vis数组做标记,vis[x][y] = a表示坐标为\((x,y)\)的点已经被高度为a的连通块搜索过了。

然后搜索周围的上下左右八个点,同时保证没有越界,且没有被同种连通块搜过,统计返回值的情况:

如果都是 1,那么返回 1;

如果都是 0,那么返回 0;

如果有 1 和 0,或者有 -1,那么返回 -1。

第二种:非连通块点

直接返回 a[x][y] > num 的值。

代码

#include<bits/stdc++.h>

#define MAXn 1010

using namespace std;

int n;
int a[MAXn][MAXn];//图中各点高度 
int vis[MAXn][MAXn];//标记数组 
int high, low;//高的连通块个数,低的连通块个数 
int d[3] = {-1, 0, 1};//坐标增量 

int dfs(int x, int y, int num)
{
	if(a[x][y] != num)//如果是非连通块点 
		return num > a[x][y];//返回连通块是否更高 
		
	vis[x][y] = num;//做标记 
	int res = 2;//返回结果统计值
	 
	for(int i = 0; i < 3; i++)
		for(int j = 0; j < 3; j++)
		{
			if(x + d[i] < 1 || x + d[i] > n || y + d[j] < 1 || y + d[j] > n)//判断是否越界 
				continue;
			if(vis[x + d[i]][y + d[j]] == num)//判断是否被同种连通块搜过 
				continue;
				
			int tmp = dfs(x + d[i], y + d[j], num);//这个点 搜索结果 
			if(res == 2)//还没有统计过任何值,直接赋值 
				res = tmp;
			else if(tmp == 2)//搜索结果为2表示这个点周围点都被搜过了 
			    continue;
			else if(tmp == -1)//直接置为-1 
			    res = -1;
			else if(res != tmp)//不相等置为-1 
				res = -1;
		}
	return res;
}

int main()
{
	scanf("%d", &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])//是否被搜过 
				continue;
			int flag = dfs(i, j, a[i][j]);//该联通块搜索结果 
			if(flag == 1)
				high++;
			else if(flag == 0) 
				low++;
			else if(flag == 2)//有个特例需要判断一下,既图中所有点都是同高度的,那么两者同时加1 
			    low++, high++;
		}
	}
	
	printf("%d %d", high, low);//输出结果 
	
	return 0;
}
posted @ 2023-01-01 15:05  six_one  阅读(28)  评论(0编辑  收藏  举报