Java B组蓝桥杯第八届国赛:生命游戏

38 篇文章 1 订阅
32 篇文章 2 订阅


标题:生命游戏

康威生命游戏是英国数学家约翰·何顿·康威在1970年发明的细胞自动机。  
这个游戏在一个无限大的2D网格上进行。

初始时,每个小方格中居住着一个活着或死了的细胞。
下一时刻每个细胞的状态都由它周围八个格子的细胞状态决定。

具体来说:

1. 当前细胞为存活状态时,当周围低于2个(不包含2个)存活细胞时, 该细胞变成死亡状态。(模拟生命数量稀少)
2. 当前细胞为存活状态时,当周围有2个或3个存活细胞时, 该细胞保持原样。
3. 当前细胞为存活状态时,当周围有3个以上的存活细胞时,该细胞变成死亡状态。(模拟生命数量过多)
4. 当前细胞为死亡状态时,当周围有3个存活细胞时,该细胞变成存活状态。 (模拟繁殖)

当前代所有细胞同时被以上规则处理后, 可以得到下一代细胞图。按规则继续处理这一代的细胞图,可以得到再下一代的细胞图,周而复始。

例如假设初始是:(X代表活细胞,.代表死细胞)
.....
.....
.XXX.
.....

下一代会变为:
.....
..X..
..X..
..X..
.....

康威生命游戏中会出现一些有趣的模式。例如稳定不变的模式:

....
.XX.
.XX.
....

还有会循环的模式:

......      ......       ......
.XX...      .XX...       .XX...
.XX...      .X....       .XX...
...XX.   -> ....X.  ->   ...XX.
...XX.      ...XX.       ...XX.
......      ......       ......


本题中我们要讨论的是一个非常特殊的模式,被称作"Gosper glider gun":

......................................
.........................X............
.......................X.X............
.............XX......XX............XX.
............X...X....XX............XX.
.XX........X.....X...XX...............
.XX........X...X.XX....X.X............
...........X.....X.......X............
............X...X.....................
.............XX.......................
......................................

假设以上初始状态是第0代,请问第1000000000(十亿)代一共有多少活着的细胞?

注意:我们假定细胞机在无限的2D网格上推演,并非只有题目中画出的那点空间。
当然,对于遥远的位置,其初始状态一概为死细胞。

注意:需要提交的是一个整数,不要填写多余内容。

这题对我来说挺有难度。需要花些时间琢磨。

想到思路之后就好做了,给了个无边无际的图,还让统计10亿次,简单模拟用表格几次过程,发现数据毫无规律的增长,而且图的范围有限,耗时还麻烦。换条思路:

(1)如果增长毫无规律,还让模拟10亿次,这是不可能的,因此一定存在规律。

(2)无边无际的图,表格不适用,而且还分八个方向,链表也应该够呛,那就不要用结构去模拟了!!

下面代码采用一个细胞类,类内存放自己的坐标。根据题目要求,我们只需要处理活细胞以及与活细胞周围死细胞。

因此用一个单独的列表存放活细胞即可。查找活细胞方便,查找活细胞周围的死细胞时,可以通过活细胞坐标,计算出周围细胞坐标,然后判断当前活细胞列表中是否含有这个细胞,表中没有的话说明这个细胞是死细胞。

有了这个逻辑,然后就可以按要求处理活细胞以及其周围的死细胞了。处理之后得到的是新一代活细胞,前一个活细胞列表就没用了,只记录一下每一代数量,将新一代活细胞作为一个新的活细胞表,重复上述过程。

代码如下:

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class Main {
	List<Cell> alivelist=new ArrayList<Cell>();     //求存活细胞
	List<Integer> numlist=new ArrayList<Integer>(); //存每代结果,用于观察
	List<Cell> templist;                            //临时存储
	int[] dx= {-1,0,1,-1,1,-1,0,1};//横  dy与dx一一对应表示方向
	int[] dy= {-1,-1,-1,0,0,1,1,1};//竖
	//细胞类
	class Cell{
		int x,y;//x横,y纵
		public Cell(int x1,int y1) {
			this.x=x1;
			this.y=y1;
		}
		//这里重写一个equals(),用于List类内部调用
		//后面用到list.contains(cell),实质上是用cell自身的equals与list每个元素比较
		//因此这里可以按需要自定义,只要两个类的x,y一样就可以看做相同
		@Override
		public boolean equals(Object object) {
			Cell c=(Cell)object;
			return this.x==c.x&&this.y==c.y;
		}
	}
	public Main() {
		Scanner sn = new Scanner(System.in);
		int x=38,y=11;
		//每读一行,就转换一行
		for (int i = 0; i < y; i++) {
			String str=sn.nextLine().trim();
			for (int j = 0; j < x; j++) {
				//将活细胞存放
				if(str.charAt(j)=='X')alivelist.add(new Cell(j, i));
			}
		}
		//记录初始活细胞总数
		numlist.add(alivelist.size());
		//开始测试300代进行查看规律
		for(int count=0;count<300;count++) {
			//临时列表,用于存放产生的下一代
			templist=new ArrayList<Cell>();
			//遍历所有活细胞进行处理
			for(Cell c:alivelist) {
				deal(c);
			}
			//收集新一代的细胞数
			numlist.add(templist.size());
			//将新一代作为基础,开始下一代
			alivelist=templist;
		}
		//展示每一代数据观察
		for(int i=0;i<numlist.size();i++) {
			System.out.print(numlist.get(i)+"\t");
			if((i+1)%10==0)System.out.println();
		}
		System.out.println();
		//展示增量查看数据信息
		for(int i=1;i<numlist.size();i++) {
			System.out.print((numlist.get(i)-numlist.get(i-1))+"\t");
			if(i%10==0)System.out.println();
		}
	}
	//处理细胞
	public void deal(Cell cell) {
		int count = 0;
		//遍历cell周围细胞
		for(int i=0;i<8;i++) {
			Cell cell2=new Cell(cell.x+dx[i], cell.y+dy[i]);
			if(alivelist.contains(cell2)) {//统计活的
				count++;
			}else if(!templist.contains(cell2)) {//查看死细胞是否满足复活条件,进行复活加入临时列表
				int count2=0;	
				for(int j=0;j<8;j++) if(alivelist.contains(new Cell(cell2.x+dx[j], cell2.y+dy[j])))count2++;
				if(count2==3)templist.add(cell2);
			}
		}
		//满足条件加入临时列表
		if (count==2||count==3) {
			templist.add(cell);
		}
	}

	
	public static void main(String[] args) {
		new Main();
	}
}

输出结果:

36  
39  43  48  51  44  51  48  61  42  48  
50  54  55  56  42  44  47  53  54  54  
54  49  60  43  50  47  47  50  48  41  
44  48  53  56  49  56  53  66  47  53  
55  59  60  61  47  49  52  58  59  59  
59  54  65  48  55  52  52  55  53  46  
49  53  58  61  54  61  58  71  52  58  
60  64  65  66  52  54  57  63  64  64  
64  59  70  53  60  57  57  60  58  51  
54  58  63  66  59  66  63  76  57  63  
65  69  70  71  57  59  62  68  69  69  
69  64  75  58  65  62  62  65  63  56  
59  63  68  71  64  71  68  81  62  68  
70  74  75  76  62  64  67  73  74  74  
74  69  80  63  70  67  67  70  68  61  
64  68  73  76  69  76  73  86  67  73  
75  79  80  81  67  69  72  78  79  79  
79  74  85  68  75  72  72  75  73  66  
69  73  78  81  74  81  78  91  72  78  
80  84  85  86  72  74  77  83  84  84  
84  79  90  73  80  77  77  80  78  71  
74  78  83  86  79  86  83  96  77  83  
85  89  90  91  77  79  82  88  89  89  
89  84  95  78  85  82  82  85  83  76  
79  83  88  91  84  91  88  101  82  88  
90  94  95  96  82  84  87  93  94  94  
94  89  100  83  90  87  87  90  88  81  
84  88  93  96  89  96  93  106  87  93  
95  99  100  101  87  89  92  98  99  99  
99  94  105  88  95  92  92  95  93  86  

3  4  5  3  -7  7  -3  13  -19  6  
2  4  1  1  -14  2  3  6  1  0  
0  -5  11  -17  7  -3  0  3  -2  -7  

3  4  5  3  -7  7  -3  13  -19  6  
2  4  1  1  -14  2  3  6  1  0  
0  -5  11  -17  7  -3  0  3  -2  -7  
3  4  5  3  -7  7  -3  13  -19  6  
2  4  1  1  -14  2  3  6  1  0  
0  -5  11  -17  7  -3  0  3  -2  -7  

3  4  5  3  -7  7  -3  13  -19  6  
2  4  1  1  -14  2  3  6  1  0  
0  -5  11  -17  7  -3  0  3  -2  -7  
3  4  5  3  -7  7  -3  13  -19  6  
2  4  1  1  -14  2  3  6  1  0  
0  -5  11  -17  7  -3  0  3  -2  -7  

3  4  5  3  -7  7  -3  13  -19  6  
2  4  1  1  -14  2  3  6  1  0  
0  -5  11  -17  7  -3  0  3  -2  -7  
3  4  5  3  -7  7  -3  13  -19  6  
2  4  1  1  -14  2  3  6  1  0  
0  -5  11  -17  7  -3  0  3  -2  -7  

3  4  5  3  -7  7  -3  13  -19  6  
2  4  1  1  -14  2  3  6  1  0  
0  -5  11  -17  7  -3  0  3  -2  -7  
3  4  5  3  -7  7  -3  13  -19  6  
2  4  1  1  -14  2  3  6  1  0  
0  -5  11  -17  7  -3  0  3  -2  -7  

我们可以看到:前一段乱七八糟的数字是每一代的活细胞总数,后一段是每两代之间的增量

显然后一段是(这里特意输出一行10个)每3行一循环,也就是每30个一循环。

那有了这个结果我们就很容易把结果计算出来。

答案:166666713

代码:

public class Calculate{
	//一次循环变化量
	int[] num= {3,4,5,3,-7,7,-3,13,-19,6,2,4,1,1,-14,2,3,6,1,0,0,-5,11,-17,7,-3,0,3,-2,-7};
	public Calculate() {
		long a=1000000000;
		long re=a/num.length;//求出来倍数,简化计算
		long remainder=a%num.length;//求出来余数单独处理
		long sum=0;//累计和
		//求出一次循环的增量,结果是5
		for(int b:num) {
			sum+=b;
		}
		//5乘以re个循环
		sum=sum*re;
		//余数重新按一次循环处理
		for(int i=0;i<remainder;i++) {
			sum+=num[i];
		}
		//加上初始值
		sum+=36;
		System.out.println(sum);
	}

    public static void main(String[] args) {
		new Calculate();
	}
}

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值