二哥养细菌

http://acm.sjtu.edu.cn/OnlineJudge/problem/1003


题目描述

二哥不仅种苹果和花生,还养了很多细菌。二哥的细菌培养皿成方格形,边长为L。长期培养后,二哥发现了细菌繁殖的规律:最初每个格子里的细菌及其后代都会独立繁殖,每次繁殖都会在其上下左右四个相邻的格子里产生新的细菌,而已经存在的细菌在培养皿充满细菌之前都不会死亡。另外,有一些格子里可能还有抗生素,细菌在有抗生素的格子里无法繁殖。

二哥于是发明了一个游戏:取一个新的培养皿,在某些格子里放入细菌或抗生素,然后观察细菌不断繁殖直至充满整个培养皿的所有没有抗生素的格子。不过二哥已经对这个游戏厌烦了,他现在只想知道经过多少轮繁殖后,细菌会充满整个培养皿(不算有抗生素的格子)。

输入格式

第1行有1个整数,边长L。

第2行至第L+1行,每行有L个整数,取值为0、1或2。0表示格子里最初没有细菌,1表示格子里最初有细菌,2表示格子里最初有抗生素。

输出格式

输出一个整数m,表示经过m轮繁殖后,细菌会充满整个培养皿(不算有抗生素的格子)

说明

【样例解释】 第一轮繁殖:

2 1 0

1 1 1

0 1 0

第二轮繁殖:

2 1 1

1 1 1

1 1 1

【数据范围】

对于全部数据: 1L100  ,保证最终能够充满培养皿(不算有抗生素的格子)。

Sample Input

3
2 0 0
0 1 0
0 0 0

Sample Output

2


      如果是在每次遍历的过程中,当元素值为1时,其上下左右的元素值如果为0的话,则设相应的位置的元素值为1,直到遍历时没有元素值改变时,表示细菌已经充满器皿。这种方法的时间复杂度大,因为它在整个遍历的过程中会重复遍历已经遍历过的且其上下左右都是为1元素值,这样的已遍历的元素的数量会随着遍历次数的增加而增大。


      那么我们怎样来减少元素的重复遍历呢?

      可不可以在每次遍历的过程中,确定下一次需要遍历的元素的位置保存下来,那么下次只要对这些保存下来的元素遍历就可以了,如此迭代直到没有需要遍历的元素时细菌充满器皿。

这是可以的。

      在每次遍历中,当元素的值为1时,如果其相应的上下左右的值为0时,则将其相应上下左右的元素的坐标记录在一个数组里,即数组中保存了在本次遍历中从0变为1的元素,也就是下次遍历的元素的位置。

      那么这个数组的历次遍历中存储的元素数量总数小于等于L^2,因为器皿中有的位置可能放抗生素。即每个元素最多只遍历了一次,从而大大降低的时间复杂度。



代码如下:

#include <iostream>
#include <string>
using namespace std;


int main()
{
	int L;  //方形器皿边长
	cin>>L;
	int **p = new int*[L];     //二维指针
	int *x = new int[L*L];     //存放遍历中值为1的元素的横坐标
	int *y = new int[L*L];     //存放遍历中值为1的元素的纵坐标
	int *n_x = new int[L*L];   //存放下一次遍历中值为1的元素的横坐标
	int *n_y = new int[L*L];   //存放下一次遍历中值为1的元素的横坐标
	int top = 0;     //本次需要遍历的元素数
	int n_top = 0;   //下次需要遍历的元素数
	int m = 0; //记录繁殖次数

	int i = 0, j = 0;
	for(i = 0; i < L; i++)     //申请一个二维数组的内存
	{
		p[i] = new int[L];
	}

	for(i = 0; i < L; i++)
	{
		for(j = 0; j < L; j++)
		{
			cin>>p[i][j];
			if(1 == p[i][j])
			{
				x[top] = i;
				y[top] = j;
				top++;
			}
		}
	}
	
	const int d[][2] = {{-1,0}, {0,-1}, {1,0}, {0,1}};
	while(1)
	{
		for(i = 0; i < top; i++)
		{
			for(j = 0 ; j < 4; j++)
			{
				int x1 = x[i]+d[j][0];
				int y1 = y[i]+d[j][1];
				

				if( 0 > x1 || x1 >= L || 0 > y1 || y1 >=L)			
					continue;
								
				if(0 == p[x1][y1])
				{
					n_x[n_top] = x1;      //记录下一次要遍历的元素的横、纵坐标。
					n_y[n_top] = y1;      
					n_top++;
					p[x1][y1] = 1;
				}
			}
		}
		
		if(n_top == 0) break;
		for(i = 0; i<n_top;i++)
		{
			x[i] = n_x[i];
			y[i] = n_y[i];
		}
		top = n_top;
		n_top = 0;
		m++;
	}
	cout<<m;
	return 0;
}

 时间:30ms / 内存:47952kb


参考:http://www.cnblogs.com/txd0u/p/3352328.html    

这篇文章使用静态数组,运行时间更快一些,但其事先定义较大的静态数组来容纳元素,空间复杂度相比本文的用动态数组的方法大。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
二哥的Java进阶之路可以说是充满挑战的,但也充满了机遇和成长。首先,为了更好地提升自己的技术能力,二哥选择了系统地学习Java编程语言。他通过参加专业的培训课程和自主学习,深入了解了Java的基础知识,掌握了常用的语法和编码规范。 接下来,二哥积极参与了一些项目,这让他在实践中不断掌握和运用Java的各种技术。在项目中,他遇到了许多技术难题和挑战,但正是这些挑战让他有机会不断提升自己的能力和解决问题的能力。通过不断地思考、学习和实践,他逐渐掌握了JavaWeb开发、数据库设计与优化等相关技术。 除了项目经验,二哥还积极参加技术交流与分享活动,这不仅帮助他与其他开发者建立了联系,还提供了更多学习和思考的机会。他参加了一些技术大会、社区活动和技术论坛,结识了一批优秀的技术人才,听取了他们的经验分享,学习了他们的思路和方法论。 在进阶的过程中,二哥成了良好的学习习惯和思考能力。他经常通过阅读相关书籍、博客和技术文档来扩充知识面,不断关注行业的最新发展和趋势。同时,他也用工作之外的时间进行代码的编写和项目的实践,不断提升自己的实际操作能力。 通过这一系列的努力,二哥的Java技术水平得到了提升,他逐渐成为了一名技术过硬、经验丰富的Java开发工程师。在未来的道路上,他将继续保持学习的态度,不断探索和应用新的技术,为自己的职业发展注入无限的动力。他相信,只要不断努力,他的Java进阶之路将会越来越宽广。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值