《生成大网格的总数》| 豆包MarsCode刷题挑战

61 阅读3分钟

今天我们将在豆包MarsCode AI刷题平台上,完成《生成大网格的总数》算法问题, 整体使用动态规划进行解答, 选择状态迁移的角度有点特别

生成大网格的总数

image.png

解析

  1. 由于操作只能选择一个宽为1,高为N/2的子网格, 则每次修改必定针对一列
    • 一列有且仅能操作一次, 否则要么通不过,要么不符合修改规则(所选的所有单元格为0)
  2. 针对每一列, 可以通过上一列的数据进行状态迁移
    • 最初考虑到点[i][j]的可能情况, 但是这种方式会由相同的伟大网格
    • 那么就考虑到达当前列时, 最终标记为1的情况, 由于这种标记是连续的, 可以使用 [l,r] 标记范围内的节点被标记为1
    • 使用[0,0]表示当前列所有点都能访问的情况
  3. 那么就有两种情况
    • 若当前列不添加网格,则由下面转移方程:
      dp[i][0][0] = (dp[i][0][0] + dp[i - 1][l][r]) % mod;
      
    • 若当前列添加网格,则由下面转移方程:
    int newL = l == 1 ? 1 : j; //l==1 必定封堵最上面进入的入口
    int newR = r == N ? N : j + step; //r=N 必定堵住下面的入口
    dp[i][newL][newR] = (dp[i][newL][newR] + dp[i - 1][l][r]) % mod;
    
  4. tips: 这个路径没有说是一定要向下向左. 即可以向上走, 导致一段时间内一直找不出问题

具体实现

public static int solution(int N) {
    int mod = 1000000007;
    //使用标记上一次被封堵的范围{l,r} 那么就是以非这个范围之内的这样方式进入的数量
    int move = N / 2 + 1;     //操作后的格子不能重叠. N,那么有可能 N/2  + 1种操作的可能
    int step = N / 2 - 1;
    //这里的空间能够进一步压缩>>>>>>>>
    long[][][] dp = new long[N + 1][N + 1][N + 1];  //保存i处, 存在封闭范围[l,r]时通过的次数
    dp[0][2][N] = 1; //表明最开始就是除了第一格能通过,其他都不能通过
    for (int i = 1; i <= N; i++) {
        //不操作
        dp[i][0][0] = dp[i - 1][0][0];
        for (int l = 1; l <= move; l++) {
            for (int r = l + step; r <= N; r++) {
                dp[i][0][0] = (dp[i][0][0] + dp[i - 1][l][r]) % mod;
            }
        }

        //操作[l,l+step]
        for (int j = 1; j <= move; j++) {//添加[j,j+step]网格
            dp[i][j][j + step] = (dp[i][j][j + step] + dp[i - 1][0][0]) % mod;

            for (int l = 1; l <= move; l++) {
                for (int r = l + step; r <= N; r++) { //可以知道这个范围一定是大于等于N
                    if (dp[i - 1][l][r] == 0) {
                        continue;
                    }
                    int newL = l == 1 ? 1 : j; //l==1 必定封堵最上面进入的入口
                    int newR = r == N ? N : j + step; //r=N 必定堵住下面的入口
                    if (newL == 1 && newR == N) {
                        continue;
                    }
                    dp[i][newL][newR] = (dp[i][newL][newR] + dp[i - 1][l][r]) % mod;
                }
            }
        }
    }
    long result = dp[N][0][0];
    for (int l = 1; l < move; l++) { //这里可以不等于move,因为没意义
        for (int r = l + step; r < N; r++) { //不能等于N,否则到不了A[N-1][N-1]
            result = (result + dp[N][l][r]) % mod;
        }
    }
    return (int) result;
}