1 条题解

  • 0
    @ 2025-5-27 16:20:23

    解题思路

    这个问题是一个基于"石头剪刀布"规则的细胞自动机模拟问题。每一天,每个单元格会根据其相邻单元格的状态进行更新,直到达到指定的天数nn

    关键分析

    1. 游戏规则建模

      • 三种生命形式:石头(R)、剪刀(S)、布(P)
      • 胜负关系:R > S, S > P, P > R
      • 每天每个单元格检查其四个相邻位置(上、下、左、右),如果相邻单元格的生命形式可以被当前单元格击败,则将相邻单元格的状态更新为当前单元格的生命形式
    2. 数据结构选择

      • 使用二维字符数组today存储当前状态
      • 使用二维字符数组tomorrow存储下一天的状态,避免在更新过程中影响后续判断
    3. 状态更新策略

      • 每天模拟时,先将today复制到tomorrow
      • 遍历每个单元格,检查其四个相邻位置
      • 根据胜负规则更新tomorrow数组
      • 一天结束后,将tomorrow复制回today

    算法实现步骤

    1. 输入处理

      • 读取测试用例数量tt
      • 对于每个测试用例,读取网格大小rrcc,以及天数nn
      • 读取初始网格状态
    2. 模拟过程

      • 循环nn天,每天进行以下操作:
        • 初始化tomorrow数组为today的副本
        • 遍历每个单元格(i,j)(i,j)
          • 检查四个相邻位置的单元格
          • 如果相邻单元格在网格内且可以被当前单元格击败,则更新tomorrow中对应位置的值
        • tomorrow复制回today
    3. 输出结果

      • 输出nn天后的网格状态
      • 测试用例之间用空行分隔

    代码关键点解释

    1. 输入处理

      getchar(); // 消耗scanf后的换行符
      fgets(today[i], MAX_COLS, stdin); // 读取一行包括换行符
      if (today[i][c] == '\n') today[i][c] = '\0'; // 移除换行符
      
    2. 方向检查: 使用switch语句处理四个方向的邻居检查,确保每个方向的坐标计算正确:

      switch (dir) {
          case 0: nj++; break; // 右
          case 1: ni--; break; // 上
          case 2: nj--; break; // 左
          case 3: ni++; break; // 下
      }
      
    3. 胜负判断: 使用逻辑或连接三种胜负情况,简洁地实现规则:

      if ((current == ROCK && opponent == SCISSORS) ||
          (current == SCISSORS && opponent == PAPER) ||
          (current == PAPER && opponent == ROCK)) {
          tomorrow[ni][nj] = current;
      }
      
    4. 数组复制: 使用memcpy高效复制二维数组:

      memcpy(tomorrow, today, sizeof(today)); // 复制today到tomorrow
      memcpy(today, tomorrow, sizeof(today)); // 更新today为tomorrow
      
    5. 输出处理: 确保测试用例之间有且仅有一个空行:

      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
    上传者