HJ152 取数游戏

  • 题目
  • 题解(15)
  • 讨论(4)
  • 排行

中等 通过率:36.69% 时间限制:1秒 空间限制:256M

知识点dfs

校招时部分企业笔试将禁止编程题跳出页面,为提前适应,练习时请使用在线自测,而非本地IDE。

描述

一个 N×MN×M 的由非负整数构成的数字矩阵,你需要在其中取出若干个数字,使得取出的任意两个数字不相邻(若一个数字在另外一个数字相邻 88 个格子中的一个即认为这两个数字相邻),求取出数字和最大是多少。

输入描述:

第一行有一个正整数 TT(1≦T≦201≦T≦20),表示了有 TT 组数据。

对于每一组数据,第一行有两个正整数 N,MN,M(1≦N,M≦61≦N,M≦6),表示了数字矩阵为 NN 行 MM 列。

接下来 NN 行,每行 MM 个非负整数,描述了这个数字矩阵,满足 1≦ai,j≦1051≦ai,j​≦105。

输出描述:

输出共 TT 行,每行一个非负整数,输出所求得的答案。

示例1

输入:

复制代码
1
3 3
1 1 1
1 1 1
1 1 1

复制输出:

复制代码
4
cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
using int64 = long long;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int T; 
    if (!(cin >> T)) return 0;
    while (T--) {
        int n, m; 
        cin >> n >> m;
        vector<vector<int64>> a(n, vector<int64>(m));
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < m; ++j) cin >> a[i][j];
        }

        // 枚举合法行掩码
        vector<int> masks;
        int full = 1 << m;
        for (int s = 0; s < full; ++s) {
            if (s & (s << 1)) continue; // 行内相邻
            masks.push_back(s);
        }

        int S = (int)masks.size();
        // 预处理兼容列表
        vector<vector<int>> compat(S);
        for (int i = 0; i < S; ++i) {
            int p = masks[i];
            for (int j = 0; j < S; ++j) {
                int s = masks[j];
                if ((s & p) == 0) {
                    int lp = (p << 1) & (full - 1);
                    int rp = (p >> 1);
                    if ((s & lp) == 0 && (s & rp) == 0) compat[i].push_back(j);
                }
            }
        }

        // 预处理每行在掩码 s 下的行和
        vector<vector<int64>> rowSum(n, vector<int64>(S, 0));
        for (int r = 0; r < n; ++r) {
            for (int j = 0; j < S; ++j) {
                int s = masks[j];
                int64 sum = 0;
                for (int c = 0; c < m; ++c) {
                    if (s & (1 << c)) sum += a[r][c];
                }
                rowSum[r][j] = sum;
            }
        }

        const int64 NEG = (int64)-4e18;
        vector<int64> dpPrev(S, NEG), dpCurr(S, NEG);
        // 第一行
        for (int j = 0; j < S; ++j) dpPrev[j] = rowSum[0][j];
        // 后续各行
        for (int r = 1; r < n; ++r) {
            fill(dpCurr.begin(), dpCurr.end(), NEG);
            for (int i = 0; i < S; ++i) {
                if (dpPrev[i] == NEG) continue;
                for (int j : compat[i]) {
                    dpCurr[j] = max(dpCurr[j], dpPrev[i] + rowSum[r][j]);
                }
            }
            dpPrev.swap(dpCurr);
        }

        int64 ans = 0;
        for (int j = 0; j < S; ++j) ans = max(ans, dpPrev[j]);
        cout << ans << "\n";
    }
    return 0;
}
相关推荐
WolfGang0073212 小时前
代码随想录算法训练营 Day21 | 回溯算法 part03
数据结构·算法
汉克老师2 小时前
GESPC++三级考试语法知识(五、字符数组 )
c++·字符数组·gesp三级·gesp3级·字母大小写转换
程序员Shawn2 小时前
【机器学习 | 第六篇】- 机器学习
人工智能·算法·机器学习·集成学习
深邃-2 小时前
数据结构-队列
c语言·数据结构·c++·算法·html5
Rhystt2 小时前
代码随想录算法训练营第六十天|多余的边?从基础到进阶!
开发语言·c++·算法·图论
羊小猪~~2 小时前
【QT】-- QMainWindow简介
开发语言·数据库·c++·后端·qt·前端框架·求职招聘
2301_810160952 小时前
C++中的策略模式进阶
开发语言·c++·算法
keep intensify2 小时前
二叉树的直径
数据结构·算法·深度优先
-Rane2 小时前
【C++】map和set
开发语言·c++