Sicily 1171. The Game of Efil 【利用完全二叉树遍历构造序列】

题目链接在此


(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;
}


你可能感兴趣的:(sicily)