zoukankan      html  css  js  c++  java
  • 生命游戏

    康威生命游戏是英国数学家约翰·何顿·康威在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
    ",i + 1,now - last,sum);
            last = now;
            swap(p,q);
        }
        int ans = 36 + 1000000000 / 30 * add[29] + add[1000000000 % 30 - 1];
        printf("%d",ans);
    }
  • 相关阅读:
    《数据结构》2.2顺序表(sequence list)
    《算法竞赛入门经典》6.3.1二叉树-小球下落
    java_时间戳与Date_相互转化
    java事物
    Mysql如何向存在外键的数据表中插入数据
    git基本配置
    mysql时间属性之时间戳和datetime之间的转换
    【转】变量命名(简短且无歧义)
    【转】mybatis实战教程(mybatis in action),mybatis入门到精通
    [转]DAO层,Service层,Controller层、View层
  • 原文地址:https://www.cnblogs.com/8023spz/p/10664395.html
Copyright © 2011-2022 走看看