题目链接在此
(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;
}