蓝桥杯2017国赛JAVAB组 生命游戏 题解
标题:生命游戏
康威生命游戏是英国数学家约翰·何顿·康威在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网格上推演,并非只有题目中画出的那点空间。
当然,对于遥远的位置,其初始状态一概为死细胞。
注意:需要提交的是一个整数,不要填写多余内容。
package 生命游戏; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Scanner; public class Main { //文件终止符问题, 点出去再点进来,无语。。。。。 static int[][] dir = {{1,-1},{1,1},{-1,1},{-1,-1},{0,1},{0,-1},{1,0},{-1,0}}; public static void main(String[] args) { Scanner sc = new Scanner(System.in); Map<Integer, HashSet<Integer>> lifemap = new HashMap<>();//记录本轮生命体 Map<Integer, HashSet<Integer>> nmap = new HashMap<>();//记录下一轮生命体 Map<Integer, HashSet<Integer>> visit = new HashMap<>();//在每一轮中记录是否被访问过 //初始化 int row = 0;//y的值 String str; //处理输入 while(sc.hasNext()) { str = sc.nextLine(); for(int x = 0; x < str.length(); x++) { if(str.charAt(x) == 'X') { if(lifemap.containsKey(x)) {//把这个点加到map里 lifemap.get(x).add(row); }else { HashSet<Integer> nset = new HashSet<>(); nset.add(row); lifemap.put(x, nset); } } } row++; } int fans = 0; for(Integer x : lifemap.keySet()) { for(Integer y : lifemap.get(x)) { //System.out.println(x + " " + y); fans++; } } System.out.println(fans); //模拟游戏 int cnt = 0; while(cnt < 100) { for(Integer x : lifemap.keySet()) {//第一轮 for(Integer y : lifemap.get(x)) { if(visit.containsKey(x)) //在某个点周围被先访问了,直接跳过 if(visit.get(x).contains(y)) continue; if(visit.containsKey(x)) {//把这个点标记已访问 visit.get(x).add(y); }else { HashSet<Integer> nset = new HashSet<>(); nset.add(y); visit.put(x, nset); } int num = 0; //System.out.print(x + " " + y + " : "); for(int[] d : dir) {//周围八个点,第一层 int curx = x + d[0]; int cury = y + d[1]; boolean alive = false; if(lifemap.containsKey(curx)) if(lifemap.get(curx).contains(cury)) { num++; alive = true; } if(alive) continue; //System.out.print(curx + " " + cury + " : "); if(visit.containsKey(curx)) //如果被访问过,就跳过这个点 if(visit.get(curx).contains(cury)) continue; if(visit.containsKey(curx)) {//把这个点标记已访问 visit.get(curx).add(cury); }else { HashSet<Integer> nset = new HashSet<>(); nset.add(cury); visit.put(curx, nset); } int cnum = 0; for(int[] cd : dir) {//周围8个点,第二层 int cx = curx + cd[0]; int cy = cury + cd[1]; if(lifemap.containsKey(cx)) if(lifemap.get(cx).contains(cy)) { cnum++; } } //System.out.print(cnum); //System.out.println(); if(cnum == 3) { if(nmap.containsKey(curx)) {//把这个点加到map里 nmap.get(curx).add(cury); }else { HashSet<Integer> nset = new HashSet<>(); nset.add(cury); nmap.put(curx, nset); } } } //System.out.print(num); //System.out.println(); if(num < 2) { ; }else if(num >=2 && num <= 3) { if(nmap.containsKey(x)) { nmap.get(x).add(y); }else { HashSet<Integer> nset = new HashSet<>(); nset.add(y); nmap.put(x, nset); } }else{ ; } } } lifemap = new HashMap<>(); lifemap.putAll(nmap); nmap.clear(); visit.clear(); cnt++; int ans = 0; for(Integer x : lifemap.keySet()) { for(Integer y : lifemap.get(x)) { //System.out.println(x + " " + y); ans++; } } System.out.println(ans); } sc.close(); } }
将输出结果复制到excel表格中处理一下,然后找一下规律。
发现每30组是一个周期,累积增量是5,1e9/30=33333333····10。
答案就是36+33333333*5+12=166666713。
|
|
参考博客:https://blog.csdn.net/TQCAI666/article/details/80325524 博主:数学工具构造器