题目链接在此
(1)“Game of Life”,经典游戏和案例。一排排一列列格子,初始状态下,里面有一些细菌。通过数邻居(四周共8个)之中共有多少个细菌来决定下一代:如果某格子里原来有细菌,邻居有2个或3个细菌则下一代存活,否则下一代格子变空;如果某格子里原来没有细菌,邻居恰好有3个细菌则下一代生成一个细菌,否则下一代还是空的。
(2)这题里面,格子有界。难以理解的地方在于必须把整张图想象成环形的。
比如2行3列的图(1代表格子里有细菌,0代表没有):
1 1 0
0 1 1
现在扩展成4行5列的图,这样一来就能数原图格子的邻居细菌数(中间6个格子是原图,外层是邻居。我用颜色标出来,显示外层这些邻居的0或1是如何通过原图得到的。比如[1,1] [1,4] [3,1] 是通过[3,4]得到的,他们被我标成黄色),然后判断下一代的状态了:
1 0 1 1 0
0 1 1 0 1
1 0 1 1 0
0 1 1 0 1
下面源代码里的expand函数用来把原来的图扩展成环形的,方便数边界上格子的邻居个数。很容易理解是怎么回事。
(3)方法是遍历所有初始状态,然后生成下一代,与输入的图对比,统计匹配的总数。比如2*3的规模,每个格子要么有细菌(1)要么没细菌(0),共有2^(2*3)= 64种初始状态。具体方法是构建二叉树,找出000000, 000001,…,111111这64种状态。用每一种状态构造图,再按(2)的方法扩展,生成下一代,和目标对比。
源代码:
#include<stdio.h> #include<string.h> int total; int finalGrid[20][20]; const int neiRow[] = { -1, 0, 1, -1, 1, -1, 0, 1 }; const int neiCol[] = { -1, -1, -1, 0, 0, 1, 1, 1 }; void expand(int grid[][20], int rowNum, int colNum) { int i, j; for (j = 1; j <= colNum; j++) { grid[0][j] = grid[rowNum][j]; grid[rowNum + 1][j] = grid[1][j]; } for (i = 1; i <= rowNum; i++) { grid[i][0] = grid[i][colNum]; grid[i][colNum + 1] = grid[i][1]; } grid[0][0] = grid[rowNum][colNum]; grid[0][colNum + 1] = grid[rowNum][1]; grid[rowNum + 1][0] = grid[1][colNum]; grid[rowNum + 1][colNum+1] = grid[1][1]; } void nextGen(int parentGrid[][20], int rowNum, int colNum) { int tmp[20][20]; for (int i = 1; i <= rowNum; i++) { for (int j = 1; j <= colNum; j++) { int neighbor = 0; for (int k = 0; k < 8; k++) { if (parentGrid[i + neiRow[k]][j + neiCol[k]] == 1) neighbor++; } if (parentGrid[i][j] == 1) { if (neighbor == 2 || neighbor == 3) tmp[i][j] = 1; else tmp[i][j] = 0; } else if (parentGrid[i][j] == 0) { if (neighbor == 3) tmp[i][j] = 1; else tmp[i][j] = 0; } } } for (int i = 1; i <= rowNum; i++) { for (int j = 1; j <= colNum; j++) { parentGrid[i][j] = tmp[i][j]; } } } bool isTheSame(int a[][20], int b[][20], int rowNum, int colNum) { for (int i = 1; i <= rowNum; i++) { for (int j = 1; j <= colNum; j++) { if(a[i][j] != b[i][j]) return false; } } return true; } void makeParent(int rowNum, int colNum, int seq[]){ int parentGrid[20][20]; int k = 0; for (int i = 1; i <= rowNum; i++){ for (int j = 1; j <= colNum; j++) { parentGrid[i][j] = seq[k++]; } } expand(parentGrid, rowNum, colNum); nextGen(parentGrid, rowNum, colNum); if (isTheSame(parentGrid, finalGrid, rowNum, colNum)) total++; } void makeTree(int rowNum, int colNum, int seq[], int path){ if (path == rowNum * colNum) { makeParent(rowNum, colNum, seq); return; } int tmp0[16]; for (int i = 0; i < rowNum * colNum; i++) tmp0[i] = (i == path ? 0 : seq[i]); makeTree(rowNum, colNum, tmp0, path + 1); int tmp1[16]; for (int i = 0; i < rowNum * colNum; i++) tmp1[i] = (i == path ? 1 : seq[i]); makeTree(rowNum, colNum, tmp1, path + 1); } int main() { int rowNum, colNum; int bactNum; int x, y; int i, j; int caseNum = 1; while (scanf("%d%d", &rowNum, &colNum) && rowNum && colNum) { total = 0; memset(finalGrid, 0, sizeof(finalGrid)); scanf("%d", &bactNum); for (i = 1; i <= bactNum; i++) { scanf("%d%d", &x, &y); finalGrid[x + 1][y + 1] = 1; } int seq[16] = {0}; makeTree(rowNum, colNum, seq, 0); printf("Case %d: ", caseNum++); if (total == 0) printf("Garden of Eden.\n"); else printf("%d possible ancestors.\n", total); } return 0; }