【华为笔试模拟题】2026/4/10 太难了吧...动态规划

image

package org.example;

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        // 读取测试用例的组数 T
        int T = sc.nextInt();
        
        // 循环处理每一组测试用例
        for (int t = 0; t < T; t++) {
            // 读取矩阵的 行数N 和 列数M
            int N = sc.nextInt();
            int M = sc.nextInt();
            // 定义二维数组 grid 存储整个数字矩阵
            int[][] grid = new int[N][M];

            // 双层循环:读取矩阵中每一个数字
            for (int row = 0; row < N; row++) {
                for (int col = 0; col < M; col++) {
                    grid[row][col] = sc.nextInt();
                }
            }

            // ===================== 核心步骤1:生成一行的所有合法选法 =====================
            // 题目规则:同一行不能选相邻的数字 → 二进制状态不能有连续的1
            // validStates:存储所有【一行内合法】的选法(用二进制数字表示,1=选,0=不选)
            List<Integer> validStates = new ArrayList<>();
            // 遍历所有可能的选法:M列总共有 2^M 种选法(1<<M 等价于 2^M)
            //意思是当前选法例如110,和左移一位100相与运算,如果有连续1结果就不为0
            for (int state = 0; state < (1 << M); state++) {
                // 位运算判断:无连续1 → 合法状态
                // (state & (state << 1)) == 0 是判断二进制无连续1的固定公式
                if ((state & (state << 1)) == 0) {
                    validStates.add(state);
                }
            }

            // ===================== 核心步骤2:预处理每种选法的分数和 =====================
            // sum[row][state]:第row行,用state这个选法,能拿到的数字总和
            // 提前算好,后面DP直接用,不用重复计算
            int[][] sum = new int[N][1 << M];
            // 遍历每一行
            for (int row = 0; row < N; row++) {
                // 遍历这一行的所有合法选法
                for (int state : validStates) {
                    int total = 0;
                    // 遍历每一列,判断是否被选中
                    for (int col = 0; col < M; col++) {
                        // 判断:当前选法是否选中了第col列
                        // (1 << col) 是列的标记,&运算结果≠0 代表选中
                        if ((state & (1 << col)) != 0) {
                            // 选中了,就把这个数字加入总分
                            total += grid[row][col];
                        }
                    }
                    // 把当前行、当前选法的总分存起来
                    sum[row][state] = total;
                }
            }

            // ===================== 核心步骤3:定义DP数组 + 初始化 =====================
            // DP数组定义:dp[row][state] = 处理到第row行,且第row行选state状态时,最大总分
            // 二维数组原因:必须记录【行号】+【当前行选法】,才能判断和上一行是否冲突
            int[][] dp = new int[N][1 << M];
            
            // 初始化第一行:第一行没有上一行,直接等于自身选法的总分
            for (int state : validStates) {
                dp[0][state] = sum[0][state];
            }

            // ===================== 核心步骤4:DP状态转移(逐行计算最大总分) =====================
            // 从第二行开始遍历(第一行已初始化)
            for (int row = 1; row < N; row++) {
                // 枚举:当前行的所有合法选法 curr
                for (int curr : validStates) {
                    // 枚举:上一行的所有合法选法 prev
                    for (int prev : validStates) {
                        // ===================== 关键:判断两行选法是否8邻域冲突 =====================
                        // 题目规则:不能8邻域相邻 → 3个条件必须同时满足
                        // 1. prev & curr == 0:上下正对着的列不能同时选
                        // 2. prev & (curr << 1) == 0:对角线(右上)不能同时选
                        // 3. prev & (curr >> 1) == 0:对角线(左上)不能同时选
                        boolean noConflict = (prev & curr) == 0
                                && (prev & (curr << 1)) == 0
                                && (prev & (curr >> 1)) == 0;

                        // 如果两行选法不冲突,就可以转移状态
                        if (noConflict) {
                            // 状态转移公式:
                            // 当前行最大总分 = max(自身原值, 上一行最大总分 + 当前行选法的分数)
                            dp[row][curr] = Math.max(dp[row][curr], dp[row-1][prev] + sum[row][curr]);
                        }
                    }
                }
            }

            // ===================== 核心步骤5:取最终答案 =====================
            // 答案:最后一行所有合法选法中的最大总分(所有行处理完毕)
            int ans = 0;
            for (int state : validStates) {
                ans = Math.max(ans, dp[N-1][state]);
            }
            // 输出当前测试用例的答案
            System.out.println(ans);
        }
        sc.close();
    }
}
posted @ 2026-04-10 18:12  Jwwind  阅读(3)  评论(0)    收藏  举报