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

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

 

 

十亿本就是一个很大的数字,网格又是无限的,只能利用有限的空间找出规律然后才能推出答案。

用二维数组模拟网格,空间尽量大,打印第i次,比前一次和比第0次的存活数的差。

1 3 3
2 4 7
3 5 12
4 3 15
5 -7 8
6 7 15
7 -3 12
8 13 25
9 -19 6
10 6 12
11 2 14
12 4 18
13 1 19
14 1 20
15 -14 6
16 2 8
17 3 11
18 6 17
19 1 18
20 0 18
21 0 18
22 -5 13
23 11 24
24 -17 7
25 7 14
26 -3 11
27 0 11
28 3 14
29 -2 12
30 -7 5
31 3 8
32 4 12
33 5 17
34 3 20
35 -7 13
36 7 20
37 -3 17
38 13 30
39 -19 11
40 6 17
41 2 19
42 4 23
43 1 24
44 1 25
45 -14 11
46 2 13
47 3 16
48 6 22
49 1 23
50 0 23
51 0 23
52 -5 18
53 11 29
54 -17 12
55 7 19
56 -3 16
57 0 16
58 3 19
59 -2 17
60 -7 10
61 3 13
62 4 17
63 5 22
64 3 25
65 -7 18
66 7 25
67 -3 22
68 13 35
69 -19 16
70 6 22
71 2 24
72 4 28
73 1 29
74 1 30
75 -14 16
76 2 18
77 3 21
78 6 27
79 1 28
80 0 28
81 0 28
82 -5 23
83 11 34
84 -17 17
85 7 24
86 -3 21
87 0 21
88 3 24
89 -2 22
90 -7 15
91 3 18
92 4 22
93 5 27
94 3 30
95 -7 23
96 7 30
97 -3 27
98 13 40
99 -19 21
100 6 27

可以找到规律,进而求出答案:

 

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#define MAX 1000
using namespace std;
char a[20 + MAX * 2][40 + MAX * 2],b[20 + MAX * 2][40 + MAX * 2];
char (*p)[40 + MAX * 2] = a,(*q)[40 + MAX * 2] = b;
int dir[8][2] = {0,1,1,1,1,0,0,-1,-1,-1,-1,0,-1,1,1,-1};
int n = 11,m = 38,last,now,sum;
int add[100];
void change() {
    now = 0;
    for(int i = 0;i < n + MAX * 2;i ++) {
        for(int j = 0;j < m + MAX * 2;j ++) {
            int c = 0;
            for(int k = 0;k < 8;k ++) {
                int ti = i + dir[k][0];
                int tj = j + dir[k][1];
                if(ti < 0 || tj < 0 || ti >= n + MAX * 2 || tj >= m + MAX * 2 || p[ti][tj] == '.') continue;
                c ++;
            }
            if(p[i][j] == 'X') {
                if(c < 2 || c > 3) q[i][j] = '.';
                else q[i][j] = 'X';
            }
            else {
                if(c == 3) q[i][j] = 'X';
                else q[i][j] = '.';
            }
            if(q[i][j] == 'X') now ++;
        }
    }
}
int main() {
    memset(a,'.',sizeof(a));
    memset(b,'.',sizeof(b));
    for(int i = MAX;i < MAX + n;i ++) {
        if(i > MAX) getchar();
        for(int j = MAX;j < MAX + m;j ++) {
            a[i][j] = getchar();
        }
    }
    last = 36;
    for(int i = 0;i < 100;i ++) {
        change();
        sum += now - last;
        add[i] = sum;
        printf("%d %d %d\n",i + 1,now - last,sum);
        last = now;
        swap(p,q);
    }
    int ans = 36 + 1000000000 / 30 * add[29] + add[1000000000 % 30 - 1];
    printf("%d",ans);
}