1 条题解
-
0
解题思路
这个问题是一个基于"石头剪刀布"规则的细胞自动机模拟问题。每一天,每个单元格会根据其相邻单元格的状态进行更新,直到达到指定的天数。
关键分析
-
游戏规则建模:
- 三种生命形式:石头(R)、剪刀(S)、布(P)
- 胜负关系:R > S, S > P, P > R
- 每天每个单元格检查其四个相邻位置(上、下、左、右),如果相邻单元格的生命形式可以被当前单元格击败,则将相邻单元格的状态更新为当前单元格的生命形式
-
数据结构选择:
- 使用二维字符数组
today
存储当前状态 - 使用二维字符数组
tomorrow
存储下一天的状态,避免在更新过程中影响后续判断
- 使用二维字符数组
-
状态更新策略:
- 每天模拟时,先将
today
复制到tomorrow
- 遍历每个单元格,检查其四个相邻位置
- 根据胜负规则更新
tomorrow
数组 - 一天结束后,将
tomorrow
复制回today
- 每天模拟时,先将
算法实现步骤
-
输入处理:
- 读取测试用例数量
- 对于每个测试用例,读取网格大小和,以及天数
- 读取初始网格状态
-
模拟过程:
- 循环天,每天进行以下操作:
- 初始化
tomorrow
数组为today
的副本 - 遍历每个单元格:
- 检查四个相邻位置的单元格
- 如果相邻单元格在网格内且可以被当前单元格击败,则更新
tomorrow
中对应位置的值
- 将
tomorrow
复制回today
- 初始化
- 循环天,每天进行以下操作:
-
输出结果:
- 输出天后的网格状态
- 测试用例之间用空行分隔
代码关键点解释
-
输入处理:
getchar(); // 消耗scanf后的换行符 fgets(today[i], MAX_COLS, stdin); // 读取一行包括换行符 if (today[i][c] == '\n') today[i][c] = '\0'; // 移除换行符
-
方向检查: 使用switch语句处理四个方向的邻居检查,确保每个方向的坐标计算正确:
switch (dir) { case 0: nj++; break; // 右 case 1: ni--; break; // 上 case 2: nj--; break; // 左 case 3: ni++; break; // 下 }
-
胜负判断: 使用逻辑或连接三种胜负情况,简洁地实现规则:
if ((current == ROCK && opponent == SCISSORS) || (current == SCISSORS && opponent == PAPER) || (current == PAPER && opponent == ROCK)) { tomorrow[ni][nj] = current; }
-
数组复制: 使用
memcpy
高效复制二维数组:memcpy(tomorrow, today, sizeof(today)); // 复制today到tomorrow memcpy(today, tomorrow, sizeof(today)); // 更新today为tomorrow
-
输出处理: 确保测试用例之间有且仅有一个空行:
if (t > 0) printf("\n"); // 最后一个测试用例后不输出空行
#include <stdio.h> #include <string.h> #define MAX_ROWS 105 #define MAX_COLS 105 // 定义符号常量提高可读性 #define ROCK 'R' #define SCISSORS 'S' #define PAPER 'P' int main() { int t, r, c, n, i, j, k; char today[MAX_ROWS][MAX_COLS]; char tomorrow[MAX_ROWS][MAX_COLS]; // 读取测试用例数量 scanf("%d", &t); while (t--) { // 读取网格尺寸和天数 scanf("%d %d %d", &r, &c, &n); getchar(); // 消耗掉scanf后的换行符 // 读取今天的网格状态 for (i = 0; i < r; i++) { fgets(today[i], MAX_COLS, stdin); // 移除行末的换行符 if (today[i][c] == '\n') today[i][c] = '\0'; } // 模拟每一天的变化 for (k = 0; k < n; k++) { // 复制今天的状态到明天的网格 memcpy(tomorrow, today, sizeof(today)); // 遍历每个单元格 for (i = 0; i < r; i++) { for (j = 0; j < c; j++) { char current = today[i][j]; char opponent; // 检查四个方向的邻居 for (int dir = 0; dir < 4; dir++) { int ni = i, nj = j; // 计算邻居坐标 switch (dir) { case 0: nj++; break; // 右 case 1: ni--; break; // 上 case 2: nj--; break; // 左 case 3: ni++; break; // 下 } // 检查邻居是否在网格内 if (ni >= 0 && ni < r && nj >= 0 && nj < c) { opponent = today[ni][nj]; // 根据规则更新明天的状态 if ((current == ROCK && opponent == SCISSORS) || (current == SCISSORS && opponent == PAPER) || (current == PAPER && opponent == ROCK)) { tomorrow[ni][nj] = current; } } } } } // 更新今天的网格为明天的状态 memcpy(today, tomorrow, sizeof(today)); } // 输出最终结果 for (i = 0; i < r; i++) { printf("%s\n", today[i]); } // 在测试用例之间输出空行(最后一个除外) if (t > 0) printf("\n"); } return 0; }
-
- 1
信息
- ID
- 1340
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者