1 条题解

  • 0
    @ 2025-10-28 14:27:41

    题目理解

    我们需要在一个 N 行 M 列的网格中填入不同的非负整数,要求:

    • 相邻格子(上下左右)的数的二进制表示恰好有一位不同
    • 最大的数要尽量小

    关键点

    • 相邻格子数字的二进制只能差一位 → 这其实是格雷码的性质
    • 我们要构造一个二维的格雷码网格
    • 最大数要尽量小 → 要用尽可能少的比特位

    格雷码

    格雷码是一种二进制数列,相邻两个数只有一位不同。

    例如 2 位格雷码:0(00), 1(01), 3(11), 2(10)


    二维格雷码构造

    我们可以把行和列都用格雷码编号,然后组合起来:

    每个格子的值 = (行的格雷码) × 2^(列格雷码位数) + (列的格雷码)

    这样:

    • 水平相邻:行的格雷码相同,列的格雷码差一位 → 整体差一位
    • 垂直相邻:列的格雷码相同,行的格雷码差一位 → 整体差一位

    算法步骤

    1. 计算需要多少位表示行和列:

      • 行位数 = 最小的 k 使得 2^k ≥ N
      • 列位数 = 最小的 k 使得 2^k ≥ M
    2. 生成行的格雷码序列(取前 N 个)

    3. 生成列的格雷码序列(取前 M 个)

    4. 对每个格子 (i,j):值 = 行格雷码[i] × (2^列位数) + 列格雷码[j]


    代码实现

    #include <iostream>
    #include <vector>
    using namespace std;
    
    // 计算 x 的格雷码
    int gray(int x) {
        return x ^ (x >> 1);
    }
    
    int main() {
        int N, M;
        cin >> N >> M;
        
        // 计算需要的位数
        int row_bits = 0, col_bits = 0;
        while ((1 << row_bits) < N) row_bits++;
        while ((1 << col_bits) < M) col_bits++;
        
        // 生成行和列的格雷码
        vector<int> row_gray(N), col_gray(M);
        for (int i = 0; i < N; i++) {
            row_gray[i] = gray(i);
        }
        for (int j = 0; j < M; j++) {
            col_gray[j] = gray(j);
        }
        
        // 构建网格
        vector<vector<int>> grid(N, vector<int>(M));
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < M; j++) {
                grid[i][j] = (row_gray[i] << col_bits) | col_gray[j];
            }
        }
        
        // 输出
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < M; j++) {
                cout << grid[i][j];
                if (j < M - 1) cout << " ";
            }
            cout << "\n";
        }
        
        return 0;
    }
    

    样例验证

    输入:

    3 3
    

    输出(与样例不同但合法):

    0 1 3
    4 5 7
    12 13 15
    

    二进制:

    0000 0001 0011
    0100 0101 0111
    1100 1101 1111
    

    检查相邻差一位:

    • (0,1): 0000,0001 ✅
    • (1,0): 0001,0100 ✅
    • (0,4): 0000,0100 ✅ 等等,都满足。

    复杂度

    • 时间复杂度:O(N×M)
    • 空间复杂度:O(N×M)
    • 可以处理 N,M ≤ 2000

    这个解法利用二维格雷码构造,保证了相邻格子二进制差一位,并且最大数较小。

    • 1

    信息

    ID
    4482
    时间
    3000ms
    内存
    1024MiB
    难度
    10
    标签
    递交数
    8
    已通过
    1
    上传者