首页 > 其他分享 >[POI2007]GRZ-Ridges and Valleys 题解

[POI2007]GRZ-Ridges and Valleys 题解

时间:2023-01-01 15:24:29浏览次数:59  
标签:连通 Valleys int 题解 POI2007 dfs vis num res

(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;
}

标签:连通,Valleys,int,题解,POI2007,dfs,vis,num,res
From: https://www.cnblogs.com/six-one/p/17018094.html

相关文章

  • [USACO22DEC] Cow College B 题解
    洛谷P8897AcWing4821题目描述有\(n\)头奶牛,每头奶牛愿意交的最大学费位\(c_i\),问如何设置学费,可以使赚到的钱最多。\(1\len\le10^5,1\lec_i\le10^6\)做法分析......
  • 武汉工程大学第五届程序设计新生赛 I题 题解
    (2022,12,3)原题链接(来自牛客竞赛)抽象题意题目有点长,我们需要抽象出一个模型:一个长度为\(n\)的序列\(a_i\),从\(a_1\)开始向后跳,每次可以从\(a_i\)跳到下一位\(a_{i+1}\),......
  • 洛谷P4146 序列终结者 题解 splay tree
    题目链接:​​https://www.luogu.com.cn/problem/P4146​​题目大意:支持:区间更新(+x)区间翻转区间查询(最大值)解题思路:几乎和​​AcWing2437.Splay​​这题一模一样。示例程......
  • CF1770D Koxia and Game 题解
    47min时过C降智50min做不出D。果然晚上容易降智。题意不想复述,好长。linktoCF|linktoLuogu合理猜测留给后手的两个数字必须相等。证明为若不相等,则后手可以......
  • 洛谷 P2395 BBCode转换Markdown 题解
    洛谷P2395BBCode转换Markdown题解题目传送门:here.一道毒瘤的大模拟,给了你一部分的BBCode和Markdown语法,叫你转换。如下表:BBCodeMarkdown[h1]文字[/h1......
  • Codeforces Good Bye 2022 CF 1770 A~E 题解
    题目链接A.KoxiaandWhiteboards注意每一步替换操作都是强制的,而不是可选的。所以就用一个multiset维护所有的数,每次选一个最小的替换掉即可。时间复杂度\(O(nlogn)\)......
  • P4247 [清华集训2012]序列操作 题解
    线段树练手好题。直接上线段树五问:维护的信息是什么?由于\(c\le20\),我们不妨对线段树的每个节点维护一个\(f_k\)表示在对应区间里选择\(k\)个数相乘的所有方案的和......
  • 题解 CF1770B【Koxia and Permutation】
    \(k=1\)的情况是平凡的。\(k>1\)的情况,显然答案至少为\(n+1\),下面给出构造证明\(n+1\)总可以取到。可以构造\(p=[n,1,n-1,2,n-2,3,\cdots]\),此时以\(n\)作为最......
  • 题解 CF1770C【Koxia and Number Theory】
    显然,如果存在\(a_i=a_j\),则一定无解。否则,考虑每一个\(2\sim50\)的正整数\(k\),如果原数组每个数对\(k\)取模后,每种余数都出现至少两次,则无解。因为此时无论如何选......
  • 【题解】P5574 [CmdOI2019]任务分配问题
    stocmd学长orz题意P5574[CmdOI2019]任务分配问题给定一个长度为\(n\)的排列,试将它分成\(k\)段,使得每段的顺序对数量之和最小。\(n\leq2.5\times10^4,k\l......