刷题日记 2024_1_31(2)

刷题日记 2024_1_31(2)

原题链接:

1106. 山峰和山谷 - AcWing题库

在这里插入图片描述
在这里插入图片描述

题目分析

简而言之,该题也是考察连通块的题目,规定数字大小一样的才能连通(8个方向都可以),另外附加了两个条件用来判断该连通块是山谷还是山峰:如果这个连通块比周围的都要大,显然它是山峰;否则,是山谷。还有,如果整个矩阵是一个连通块,那么这个既是山谷又是山峰。

所以,我们需要在找连通块的同时,比较这个连通块和周围的大小。如果周围的都比它大,那么它就是山谷;如果周围的都比它小,那么它就是山峰;如果周围有的比它大有的比它小,那么它啥也不是

我的思路是,设置两个变量sf=0 , sg=0 分别用来统计连通块周围的比它小的,和比它大的数的个数。

如果整个连通块周围的,sf和sg都大于零(也就是既有比它大的也有比它小的),那么这个就不是山谷也不是山峰。

如果整个连通块周围的,sf大于零,sg等于零(也就是周围的都比它小),那么它就是山峰。

如果整个连通块周围的,sg大于零,sf等于零(也就是周围的都比它大),那么它就是山谷。

完整代码如下:

#include<bits/stdc++.h>
#define x first
#define y second

using namespace std;
typedef pair<int, int> PII;
const int N = 1010, M = N * N;
int n;
int mp[N][N];
PII q[M];
bool st[N][N];
int ans1 = 0, ans2 = 0;

void bfs(int sx, int sy)
{
	int sf = 0, sg = 0;
	int hh = 0, tt = 0;
	q[0] = { sx,sy };
	st[sx][sy] = 1;
	while (hh <= tt)
	{
		PII t = q[hh++];
		for (int i = t.x - 1; i <= t.x + 1; i++)
		{
			for (int j = t.y - 1; j <= t.y + 1; j++)
			{
				if (i == t.x && j == t.y)
					continue;
				if (i <= 0 || i > n || j <= 0 || j > n)
					continue;
				
				if (mp[i][j] < mp[t.x][t.y])
				{
					sf++;
					continue;
				}
				if (mp[i][j] > mp[t.x][t.y])
				{
					sg++;
					continue;
				}
				if (st[i][j])			//注意要在这里判断是否标记过!!!
					continue;
				q[++tt] = { i,j };
				st[i][j] = 1;
			}
		}
	}
	if (sf > 0 && sg > 0)
	{
		;
	}
	else if (sg==0 && sf == 0)
	{
		ans1++; ans2++;
	}
	else if (sg == 0 && sf > 0)
	{
		ans1++;
	}
	else
	{
		ans2++;
	}
	return;
}

int main()
{
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= n; j++)
		{
			cin >> mp[i][j];
		}
	}

	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= n; j++)
		{
			if (!st[i][j])
			{
				bfs(i, j);
			}
		}
	}
	cout << ans1 << " " << ans2 << endl;
	return 0;
}

关于debug

这道题整体思路也比较清晰,但是实现起来有一个比较坑的点:bfs的时候,if(st[i][j]=0) conotinue; 这段代码应该放到哪里?

关于debug

这道题整体思路也比较清晰,但是实现起来有一个比较坑的点:bfs的时候,if(st[i][j]=0) conotinue; 这段代码应该放到哪里?

应该放在比较大小的那段代码的下面!!! 因为就算某个元素已经被遍历过了,但是它还是需要跟正在遍历的连通块做比较大小的!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值