洛谷 山峰和山谷 BFS flood-fill 分类讨论

🍑 算法题解专栏


🍑 山峰和山谷

题目描述

给定一个N*N的地图,每个方格(i,j)都有一个高度Wij。若两个方格有公共顶点,则称它们是相邻的。

例如,与(i,j)方格相邻的格子有(i−1, j−1),(i−1,j),(i−1,j+1),(i,j−1),(i,j+1),(i+1,j−1),(i+1,j),(i+1,j+1)。

定义山峰和山谷:

1、均由地图上一个连通块组成。连通块指块里任意方格与块中至少一个方格相邻。

2、连通块里所有方格高度相同。

3、连通块周围的方格(与其相邻但不属于连通块的方格)若高度均大于连通块的高度,则称连通块为山谷;若高度均小于则称连通块为山峰。
求地图里山谷和山峰的数量。

(注:如果整张地图的高度均相等,则整张地图既是一个山谷也是一个山峰。)

输入格式

第一行包含一个整数N,代表地图的大小。

接下来N行每行包含N个数,表示地图每个方格的高度。

输出格式

输出仅为一行,包含两个整数,分别为山峰和山谷的数量。

样例 #1

样例输入 #1

5
5 7 8 3 1
5 5 7 6 6
6 6 6 2 8
5 7 2 5 8
7 1 0 1 7

样例输出 #1

3 3

提示

山峰

5 7 8 3 1

5 5 7 6 6

6 6 6 2 8

5 7 2 5 8

7 1 0 1 7

山谷

5 7 8 3 1

5 5 7 6 6

6 6 6 2 8

5 7 2 5 8

7 1 0 1 7

【数据规模】

2<=N<=1000


🍑 输入超 10万 使用快读
🍑 库里的 Linkedlist 比 数组模拟队列 对内存的消耗更小,但运行时间会变长(猜测)
🍑 同一连通块的才需要判重

import java.io.*;
import java.util.*;

public class Main
{
	static int N = 1010, n;
	static int[][] h = new int[N][N];
	static boolean[][] st = new boolean[N][N];
//	static Node[] q = new Node[N * N];
	static boolean hasLow, hasHigh;// 表示连通块周围有无比它低、高的点

	static int[] dx = { -1, 0, 1, 0 };
	static int[] dy = { 0, -1, 0, 1 };

	static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
	static BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out));

	static class Node
	{
		int x;
		int y;

		public Node(int x, int y)
		{
			super();
			this.x = x;
			this.y = y;
		}
	}

	static void bfs(int sx, int sy)
	{
		st[sx][sy] = true;
		int hh = 0;
		int tt = -1;
//		q[++tt] = new Node(sx, sy);
		// LinkedList 相对于 数组模拟 队列 省空间
		Queue<Node> q = new LinkedList<Node>();
		q.add(new Node(sx, sy));
		while (!q.isEmpty())
		{
//			Node t = q[hh++];
			Node t = q.poll();
			int x = t.x;
			int y = t.y;
//			st[x][y] = true;
			for (int xx = x - 1; xx <= x + 1; xx++)
			{
				for (int yy = y - 1; yy <= y + 1; yy++)
				{
					if (xx < 0 || xx >= n || yy < 0 || yy >= n)
						continue;
//					AC 代码
					//先处理特殊情况,无需判断是否是已经被遍历过的点
					if (h[xx][yy] != h[x][y])
					{
						if (h[xx][yy] > h[x][y])
							hasHigh = true;
						else
							hasLow = true;
					} 
					//只有在处理同一连通块的点才需要判断是否有重复遍历
					else if (!st[xx][yy])
					{
						st[xx][yy] = true;
//						q[++tt] = new Node(xx, yy);
						q.add(new Node(xx, yy));
					}

//					代码2
//					if (h[xx][yy] == h[x][y] && !st[xx][yy])
//					{
//						st[xx][yy] = true;
						q[++tt] = new Node(xx, yy);
//						q.add(new Node(xx, yy));
//					} else
//					{
//						if (h[xx][yy] > h[x][y])
//							hasHigh = true;
//						else if (h[xx][yy] < h[x][y]) // 这里还是得避免 h[xx][yy] == h[x][y] 的情况
//							hasLow = true;
//					}

//					代码1
//					if (h[xx][yy] < h[x][y])
//						hasLow = true;
//					else if (h[xx][yy] > h[x][y])
//						hasHigh = true;
//					else if (!st[xx][yy] && h[xx][yy] == h[x][y])
//					{
//						st[xx][yy] = true;// 只有同一个连通块才进行标记
						q[++tt] = new Node(xx, yy);
//						q.add(new Node(xx, yy));
//					}
				}
			}
		}
	}

	public static void main(String[] args) throws IOException
	{
		n = Integer.parseInt(in.readLine());
		for (int i = 0; i < n; i++)
		{
			String[] ss = in.readLine().split(" ");
			for (int j = 0; j < n; j++)
				h[i][j] = Integer.parseInt(ss[j]);
		}
		int peek = 0;
		int valley = 0;
		for (int i = 0; i < n; i++)
			for (int j = 0; j < n; j++)
				if (!st[i][j])
				{
					hasLow = false;
					hasHigh = false;
					bfs(i, j);
					if (!hasHigh)
						peek++;
					if (!hasLow)
						valley++;
				}
		out.write(peek + " " + valley);
		out.flush();
//		System.out.println(peek + " " + valley);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值