刷题日记 2024_1_31(2)
原题链接:
题目分析
简而言之,该题也是考察连通块的题目,规定数字大小一样的才能连通(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;
这段代码应该放到哪里?
应该放在比较大小的那段代码的下面!!! 因为就算某个元素已经被遍历过了,但是它还是需要跟正在遍历的连通块做比较大小的!