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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章