蓝桥杯——生命游戏(找规律)

康威生命游戏是英国数学家约翰·何顿·康威在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网格上推演,并非只有题目中画出的那点空间。
当然,对于遥远的位置,其初始状态一概为死细胞。

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

思路:

这道题一看找1000000000代的情况,他要么是循环的,要么是有规律的,所以就先打一下表观察观察

//打表观察前100代
#include<iostream>
using namespace std;
char tmp[100][100];
int mov[8][2]={{1,0},{-1,0},{0,1},{0,-1},{1,1},{1,-1},{-1,1},{-1,-1}};
char s[100][100]={
".........................................................",
".........................................................",
".........................................................",
".........................................................",
".........................................................",
".........................................................",
".........................................................",
".........................................................",
".........................................................",
".........................................................",
"...................................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................................",
".........................................................",
".........................................................",
".........................................................",
".........................................................",
".........................................................",
".........................................................",
".........................................................",
".........................................................",
".........................................................",
".........................................................",
};
int main(){
	int t=100;
	int n=29,m=57; 
	int sum=0;
	cout<<"*************"<<1<<"****************"<<endl;
    for(int i=0;i<n;i++){
    	for(int j=0;j<m;j++){
    		if(s[i][j]=='X')
    		    sum++;
    		cout<<s[i][j];
		}
		cout<<endl;
	}
		cout<<endl<<"____________________"<<sum<<"_____________________"<<endl;
	while(t--){
		cout<<endl;
		cout<<endl;
		cout<<"*************"<<101-t<<"****************"<<endl;
		cout<<endl;
		for(int i=0;i<n;i++){
			for(int j=0;j<m;j++){
				int num=0;
				for(int k=0;k<8;k++){//记录八个方向的情况 
					int fx=i+mov[k][0];
					int fy=j+mov[k][1];
					if(fx<0||fx>=n||fy<0||fy>=m)
					    continue;
					if(s[fx][fy]=='X')
					    num++;
				}
			    if(s[i][j]=='X'){
					if(num==2||num==3)
						tmp[i][j]='X';
					else
						tmp[i][j]='.';
				}
				else if(s[i][j]=='.'){
					if(num==3)
						tmp[i][j]='X';
					else
						tmp[i][j]='.';
				}
			}
		}
		int count=0;
		for(int i=0;i<n;i++){
			for(int j=0;j<m;j++){
				s[i][j]=tmp[i][j];
				if(s[i][j]=='X')
				    count++;
				cout<<s[i][j];
			}
			cout<<endl;
		}
		cout<<endl<<"____________________"<<count<<"_____________________"<<endl;
	}
	return 0;
} 

根据前100代的结果可以发现

第0代和代30 代的上边图形完全相同,就是第31代下边多了一小块图形

第0代:

第30 代:

 

我们还可以发现第1代和代31 代也有这样的规律

但是整张图是无限大的,所以我们就要考虑多出来的小图形对以后的图形有什么影响,所以我们就可以把原来的图形放大,再次观察 

然后我们发现这个小图形是没有影响的

所以我们可以得出规律,这个图形是30代为一个规律,每增加30代,就增加5个存活的

所以我们可以对1000000000代进行运算

#include<iostream>
using namespace std;
int main(){
	long long n=1000000000;
	cout<<n/30<<endl;
	cout<<n%30<<endl;
	long long sum=48;//第10代的数量 
    sum=sum+(n/30)*5;
	cout<<sum<<endl;
}

题目答案:166666713

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值