2017年第八届蓝桥杯Java程序设计本科B组决赛 生命游戏(结果填空)

2017年第八届蓝桥杯Java程序设计本科B组决赛个人题解汇总:

https://blog.csdn.net/daixinliangwyx/article/details/90184941

 

第二题

标题:生命游戏

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


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


解法:题目要求十亿代,所以肯定是不能直接模拟每一代的,毕竟图也开不了这么大,因此考虑繁殖是否存在某种规律。先将初始状态的图扩大一点使初始状态在整个图的中间,方便后续繁殖扩散,先模拟一些代数的繁殖,观察每一代存活细胞的个数与上一代的差别,将结果输出到txt文件中,可以发现,前几代(从第一代开始)的差别是3、4、5、3、-7、7...,而从31代开始的差别是3、4、5、3、-7、7...,从61代开始的差别又是3、4、5、3、-7、7...,因此可以知道,细胞繁殖的差别每过30代又重复一次,而每经过30代的繁殖后存活细胞的数量就增加5,因此就可以来直接计算十亿代后的存活细胞数量了。

模拟100代繁殖的代码:

#include<bits/stdc++.h>
using namespace std;
char Map[50][100], next[50][100];
int len, n = 50, m = 100, sum, presum;
string s;
int dir[8][2] = {-1, -1, -1, 0, -1, 1, 0, -1, 0, 1, 1, -1, 1, 0, 1, 1};
void dfs(int x, int y) {
  sum = 0;
  if(x == n && y == 0) {
    for (int i = 0; i < n; i++) {
      for (int j = 0; j < m; j++) {
//        cout << next[i][j];
        if (next[i][j] == 'X') sum++;
      }
//      cout << endl;
    }
    cout << "存活细胞数量: " << sum << "  比上一代繁殖了 " << sum-presum << endl;
    presum = sum;
    return;
  }
  int num = 0;
  for(int i = 0; i < 8; i++) {
    int nextx = x + dir[i][0];
    int nexty = y + dir[i][1];
    if (nextx >= 0 && nextx < n && nexty >= 0 && nexty < m && Map[nextx][nexty] == 'X') num++;
  }
  if (Map[x][y] == '.' && num == 3) next[x][y] = 'X';
  else if (Map[x][y] == 'X' && (num < 2 || num > 3)) next[x][y] = '.';
  else
    next[x][y] = Map[x][y];
  if (y+1 >= m) dfs(x+1, 0);
  else
    dfs(x, y+1);
}
int main() {
  freopen("F:\\out.txt", "w", stdout); //输出重定向,输出数据将保存在F盘中的out.txt文件中
  for (int i = 0; i < n; i++)
    for (int j = 0; j < m; j++)
      Map[i][j] = '.';
  sum = 0;
  for (int i = 11; i < 22; i++) {
    getline(cin, s);
    len = s.size();
    for (int j = len; j < len*2; j++) {
      Map[i][j] = s[j-len];
      if (Map[i][j] == 'X') sum++;
    }
  }
  cout << "第0代:";
//  for (int i = 0; i < n; i++) {
//    for (int j = 0; j < m; j++)
//      cout << Map[i][j];
//    cout << endl;
//  }
  cout << "存活细胞数量: " << sum << "  开始繁殖 " << endl;
  presum = sum;
  for (int i = 1; i < 100; i++) {
    cout << "第" << i << "代: ";
    dfs(0, 0);
    for (int ii = 0; ii < n; ii++)
      for (int jj = 0; jj < m; jj++)
        Map[ii][jj] = next[ii][jj];
  }
  fclose(stdout);//关闭输出重定向 
  return 0;
}

计算答案:

#include<bits/stdc++.h>
using namespace std;
long long add[31] = {0, 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};
int main() {
  long long ans = 36;
  ans += 1000000000 / 30 * 5;//先算有多少个30代,每代增加5个也就是再*5,千万不能先乘再除因为这样会算错代数 
  for (long long i = 1; i <= 1000000000%30; i++)
    ans += add[i];
  cout << ans << endl;
  return 0;
}

答案:166666713

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值