洛谷P3456 [POI2007]GRZ-Ridges and Valleys 题解

题目传送门https://www.luogu.com.cn/problem/P3456

题目大意:

给定一个 n×n 的网格状地图,每个方格 (i,j) 有一个高度 w[i][j]。如果两个方格有公共顶点,则它们是相邻的。

定义山峰和山谷如下:

  • 均由地图上的一个连通块组成;
  • 所有方格高度都相同;
  • 周围的方格(即不属于山峰或山谷但与山峰或山谷相邻的格子)高度均大于山谷的高度,或小于山峰的高度。

求地图内山峰和山谷的数量。特别地,如果整个地图方格的高度均相同,则整个地图既是一个山谷,也是一个山峰。

思路:

对每一个联通快进行广搜,判断其是山峰还是山谷。

细节见代码,代码如下(个人感觉注释的还算比较详细的,适合新手)

#include<bits/stdc++.h>
using namespace std;
#define int long long//不良习惯( 

int n,a[1050][1050],vis[1050][1050];//a是输入的,vis是标记是否搜过以及第几轮搜过
int flag1,flag2,cnt1,cnt2,uwu;//flag在bfs时候使用,cnt2山峰数量,cnt1山谷数量,uwu广搜判断标记时用 
int fx[8]={0,0,1,-1,1,1,-1,-1};
int fy[8]={1,-1,0,0,-1,1,-1,1};//方向数组 
struct qwq
{
	int x,y;
}tool1,tool2;//结构体存点,之后bfs有用 
void bfs(int x,int y,int k)//x,y是坐标,k是当前连通块内的值 
{
	queue<qwq>q;//队列 
	tool1.x=x;
	tool1.y=y;
	q.push(tool1);//bfs到的初始点入队 
	while(!q.empty())//平平无奇的bfs 
	{
		tool2=q.front();//取出队首 
		q.pop();//出队(不出会死循环) 
		int tx=tool2.x;
		int ty=tool2.y;
		for(int i=0;i<8;i++)//各个方向 
		{
			int xx=tx+fx[i];
			int yy=ty+fy[i];
			if(xx<=0||yy<=0||xx>n||yy>n)	continue;//边界 
			if(vis[xx][yy]==uwu)	continue;//防死循环(本次循环已搜过了) 
			if(a[xx][yy]==k)//值相等,即为在同一个块里 
			{
				vis[xx][yy]=uwu;
				tool1.x=xx;
				tool1.y=yy;
				q.push(tool1);//入队,搜索 
				continue;
			}
			if(a[xx][yy]>k)	flag1=1;//有比它高的
			if(a[xx][yy]<k)	flag2=1;//有比它低的 
		}
	}
	if(flag1&&!flag2)	cnt1++;//周围只有比它高的,没有比它低的即为山谷 
	if(!flag1&&flag2)	cnt2++;//周围只有比它低的,没有比它高的即为山谷 
	if(!flag1&&!flag2)	cnt1++,cnt2++;//对应题中特殊要求(相当于特判所有高度相等的情况) 
}
signed main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			cin>>a[i][j];
		}
	}//输入 
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			if(vis[i][j])	continue;//搜过就不搜了 
			vis[i][j]=++uwu;
			flag1=0;
			flag2=0;//flag清零 
			bfs(i,j,a[i][j]);//广搜 
		}
	}
	cout<<cnt2<<" "<<cnt1<<endl;//是空格不是换行(我因为这个调了半天) 
	return 0;
}

 (蒟蒻第一篇题解,求支持qwq,如果有错误的地方也求大佬指出,谢谢

  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值