算法 — 扩散

题目描述

本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。

        小蓝在一张无限大的特殊画布上作画。

        这张画布可以看成一个方格图,每个格子可以用一个二维的整数坐标表示。

        小蓝在画布上首先点了一下几个点:(0, 0), (2020, 11), (11, 14), (2000, 2000) 。只有这几个格子上有黑色,其它位置都是白色的。

        每过一分钟,黑色就会扩散一点。具体的,如果一个格子里面是黑色,它就会扩散到上、下、左、右四个相邻的格子中,使得这四个格子也变成黑色(如果原来就是黑色,则还是黑色)。

        请问,经过 2020 分钟后,画布上有多少个格子是黑色的。

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 128M

解题思路

        这是一道第十一届的蓝桥杯国赛题,是一道运用 BFS 广度优先搜索算法思想求解的题目,所处位置是第二道题,总体难度简单,接下来讲简单介绍求解思路。

        首先转换坐标参照物,题目描述的坐标是按照数学二维坐标轴而言,需要转化为编程中二维数组的坐标。

        从上图可以看出,由于 x 最小值为 -2020,但是二维数组下标不允许出现负数,故将数学二维坐标的坐标值进行平移操作,使得下标值不会出现负数即可。这里转化规则取:二维数组x = 数学x + 2500,二维数组y = 4500 - 数学y,转化后便开始遍历。该算法的 Java 代码实现如下:

public class Main{
		
		//矩阵规模较上面分析的偏大一点确保下标不越界,用以记录该点是否为黑色,即该点是否遍历过
		public static boolean[][] record = new boolean[10000][10000];
		
		//记录黑色点个数
		public static int count;
		
		//树结点
		public static class Node {
			int x, y, dis;//x 与 y 为坐标,dis 表示该点到源点的距离
			public Node() {}
			public Node(int x, int y, int dis) {
				this.x = x;
				this.y = y;
				this.dis = dis;
			}
		}
		
		public static void main(String[] args) {
			
//			int[][] source = {
   
   {0,0},{2020,11},{11,14},{2000,2000}};//数学二维坐标轴下的坐标
			
			int[][] dir = {
   
   {-1,0},{0,1},{1,0},{0,-1}};//模拟方向的数组
			
			count = 4;//将个数初始化为4
			
			Queue<Node> query = new LinkedList<Node>();//创建队列用以存储当前结点
			
			/**
			 * 将源点加入到队列中
			 */
			query.add(new Node(2500, 4500, 0));
			query.add(new Node(4520, 4489, 0));
			query.add(new Node(2511, 4486, 0));
			query.add(new Node(4500, 2500, 0));
			
			/**
			 * 初始化访问数组
			 */
			record[4019][2019] = true;
			record[4005][2030] = true;
			record[4008][4039] = true;
			record[2019][4019] = true;
			
			//开始广度优先搜索遍历
			while(!query.isEmpty()) {
				Node node = query.poll();
				for(int i = 0; i < 4; i++) {
					//对当前队列头结点进行四个方向的扩散
					Node next = new Node();
					next.x = node.x + dir[i][0];
					next.y = node.y + dir[i][1];
					next.dis = node.dis + 1;//距离源点距离 + 1
					//判断是否没有遍历过且距离源点距离小于或等于 2020
					if(!record[next.x][next.y] && next.dis <= 2020) {
						record[next.x][next.y] = true;//标记当前遍历的点已经访问过
						count++;//计数器 + 1
						query.add(next);//将该点加入队列
					}
				}
			}
			System.out.println(count);
		}
}

猜你喜欢

转载自blog.csdn.net/m0_59705760/article/details/124619233
今日推荐