生命游戏

康威生命游戏是英国数学家约翰·何顿·康威在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网格上推演,并非只有题目中画出的那点空间。

当然,对于遥远的位置,其初始状态一概为死细胞。

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



首先10亿次,暴力了一波,发现几分钟没出来结果,然后打表看了下结果(每次记录下一次状态比上一次多的个数,也就是记录的值是此时的状态的总数减去上一个状态的总数,)

//生命游戏
import java.math.BigInteger;
import java.util.*;
public class Main3 {
	static char[][] mp = new char[300][300];
	static int[] dx = {1, 1, 1, -1, -1, -1, 0, 0};
	static int[] dy = {1, -1, 0, 1, -1, 0, 1, -1};
	static ArrayList<Integer> result = new ArrayList<Integer>();
	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		ArrayList<point> list = new ArrayList<point>();//当前的所有的点
		ArrayList<point> tmp = new ArrayList<point>();//过渡用
		int n = 11, m = 0;
		for (int i = 0; i < 11; i++) {
			String s = in.next();
			m = s.length();
			for (int j = 0; j < s.length(); j++) {
				mp[i][j] = s.charAt(j);
				if (mp[i][j] == 'X') {
					list.add(new point(i, j));
				}
			}
		}
		
		
		for (int p = 0; p < 200; p++) {//循环次数
			result.add(list.size());
			tmp = new ArrayList<point>();
			for (int i = 0; i < list.size(); i++) {//遍历当前所有存活的点
				point cas = list.get(i);//遍历当前这个存活的点的周围的8个点
				int ans = 0;
				for (int j = 0; j < 8; j++) {
					int xx = cas.x + dx[j];
					int yy = cas.y + dy[j];
					if (list.contains(new point(xx, yy))) ans++;
					else if (round(new point(xx, yy), list)) {
						if (!tmp.contains(new point(xx, yy))) tmp.add(new point(xx, yy));
					}
				}
				if (ans < 2 || ans > 3) continue;
				if (ans == 2 || ans == 3 && !tmp.contains(cas)) tmp.add(cas);
			}
			list = tmp;
		}
		//check
		for (int i = 1; i < result.size(); i++) {
			System.out.print(result.get(i) - result.get(i - 1) + " ");
			
		}
		
		int ans = 0;
		//最后输出所有的点
//		System.out.println(list.size());
	}
	private static boolean round(point point, ArrayList<point> list) {
		int ans = 0;
		for (int i = 0; i < 8; i++) {
			int xx = point.x + dx[i];
			int yy = point.y + dy[i];
			if (list.contains(new point(xx, yy))) ans++;
		}
		if (ans == 3) return true;
		return false;
	}
	static class point {
		int x;
		int y;
		point() {}
		point(int x, int y) {
			this.x = x;
			this.y = y;
		}
		@Override
		public int hashCode() {
			final int prime = 31;
			int result = 1;
			result = prime * result + x;
			result = prime * result + y;
			return result;
		}
		@Override
		public boolean equals(Object obj) {
			if ((point)obj instanceof point) {
				if (((point)obj).x == this.x && ((point)obj).y == this.y) {
					return true;
				}
			}
			return false;
		}
		
	}
}

得到以下结果:

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 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 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 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 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 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 3 4 5 3 -7 7 -3 13 -19 6 2 4 1 1 -14 2 3 6 1 

仔细一看我们发现,这个是有重复的那么就不需要进行10亿次了;

进行转换和打表如下:166666713

public class Main {
	//变化的序列
	static int[] change = {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};
	public static void main(String[] args) {
		int origin = 36;
		int re_all = 0;
		for (int i = 0; i <= 30; i++) {
			re_all += change[i];
		}
		//每经过30次变化,存活的数量的变化是origin + re_all;
		int k = 1000000000/30;//经过30次变化的次数;
		int yu = 1000000000%30;
		
		int ans = 0;//最后的存活总数
		ans = (origin + re_all * k);
		
		for (int i = 1; i <= yu; i++) {
			ans = ans + change[i];
		}
		System.out.println(ans);
	}
}

猜你喜欢

转载自blog.csdn.net/qq_34649947/article/details/80406019