题目链接

题目

题目描述

这里有一个n*m的矩阵,请你选出其中k个子矩阵,使得这个k个子矩阵分值之和最大。

注意:选出的k个子矩阵 不能相互重叠。

输入描述

第一行为n,m,k(1 ≤ n ≤ 100,1 ≤ m ≤ 2,1 ≤ k ≤ 10),

接下来n行描述矩阵每行中的每个元素的分值(每个元素的分值的绝对值不超过32767)。

输出描述

只有一行为k个子矩阵分值之和最大为多少。

示例1

输入

3 2 2
1 -3
2 3
-2 3

输出

9

题解

知识点:线性dp。

发现 \(m=1\) 时,就是 \(k\) 串最大和。

这里解释一下 \(k\) 串最大和的做法,有三种状态设置:取第 \(i\) 个数,共取了 \(j\) 串;考虑到第 \(i\) 个数,共取了 \(j\) 串;考虑到第 \(i\) 个数,共取了 \(j\) 串,第 \(i\) 个数的状态为0/1(不取/取)。

  1. 状态转移方程是 \(dp[i][j] = \max(dp[u][j-1],dp[i-1][j]) + a[i],0 \leq u \leq i-1\) ,表示 \(a[i]\) 独立一串和 \(a[i]\) 和前面串起来取最优解,时间复杂度是 \(O(n^2k)\) ,通过前缀最大值优化可以到 \(O(nk)\) 。

  2. 状态转移方程是 \(dp[i][j] = \max (dp[u][j-1]+sum[i] - sum[u],dp[i-1][j]), 0 \leq u \leq i-1\) ,表示选 \([u+1 , i]\) 一串和不选优解,时间复杂度是 \(O(n^2k)\)。

  3. 状态转移方程是:

    \[\begin{aligned}
    dp[i][j][0] &= \max (dp[i-1][j][1],dp[i-1][j][0])\\
    dp[i][j][1] &= \max(dp[i-1][j][1],dp[i-1][j-1][1],dp[i-1][j-1][0])
    \end{aligned}
    \]

    表示不选就在前面的情况取最大值,选就在前面选后串一起或者在前面选后独立成一串或者前面不选独立成串中取最大值。时间复杂度是 \(O(nk)\) 。

要注意的是如果不允许取空串需要赋值负无穷且 \(k=0\) 的初态为 \(0\),如果允许则默认 \(0\) 即可。

现在扩展到 \(m=2\) 。也有三种设置:取第一列的第 \(i\) 个数和第二列的第 \(j\) 个数,共取了 \(u\) 个矩阵;考虑到第一列的第 \(i\) 个数和第二列的第 \(j\) 个数,共取了 \(u\) 个矩阵;考虑到第 \(i\) 行,共取了 \(j\) 个矩阵,第 \(i\) 行状态是 0/1/2/3/4(都不取\取第一列\取第二列\都取但不同块\都取成一块)。

这里写的是第二种,实际上第一种和第二种相似。第三种复杂度是 \(O(nk)\) ,但写起来麻烦,但可用矩阵运算优化写法。

转移方程为:

\[dp[i][j][u] = \max
\left \{
\begin{array}{l}
dp[v][j][k-1]+sum[i][1]-sum[v][1] &,0\leq v\leq i-1\\
dp[i][v][k-1]+sum[j][2]-sum[v][2] &,0\leq v \leq j-1\\
dp[v][v][k-1]+sum[i][1]-sum[v][1]+sum[j][2]-sum[v][2] &,i = j \and 0\leq v \leq i-1\\
dp[i-1][j][k] &,i\geq 1\\
dp[i][j-1][k] &,j\geq 1
\end{array}
\right.
\]

分别指:

  1. 选第一列 \([v+1,i]\) 作为矩阵。
  2. 选第二列 \([v+1,j]\) 作为矩阵。
  3. 在 \(i=j\) 下还能选两列 \([v+1,i]\) 作为矩阵。
  4. 不选第一列。
  5. 不选第二列。

这道题数据不太行,其他题解有说可以有空矩阵,我这里写的是包括空矩阵的,但实际上初始化负无穷,\(k=0\) 初态为 \(0\) 做不包含空矩阵的,也是对的。

时间复杂度 \(O(n^2k)\)

空间复杂度 \(O(n^2k)\)

代码

#include <bits/stdc++.h>

using namespace std;

int a[107][10], dp[107][107][17], sum[107][10];

int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int n, m, k;
cin >> n >> m >> k;
for (int i = 1;i <= n;i++)
for (int j = 1;j <= m;j++)
cin >> a[i][j], sum[i][j] = a[i][j] + sum[i - 1][j];
///不需要从0开始,因为如果从(0,j,k-1)转移到(i,j,k),则有(min(i,j),min(i,j),k-1)到(i,j,k)的转移
///而形如(l,l,k)的状态是可以从 (1,1,1) 开始推的,因此所有都可以从(1,1,1)开始
///感觉好奇怪,还是从(0,0,1)开始舒服
///再者可以选空矩阵,因此不需要初始化负无穷
for (int i = 0;i <= n;i++) {
for (int j = 0;j <= n;j++) {
for (int u = 1;u <= k;u++) {
dp[i][j][u] = max(dp[max(0, i - 1)][j][u], dp[i][max(0, j - 1)][u]);///不选i或j
for (int v = 0;v < i;v++) dp[i][j][u] = max(dp[v][j][u - 1] + sum[i][1] - sum[v][1], dp[i][j][u]);///选i
for (int v = 0;v < j;v++) dp[i][j][u] = max(dp[i][v][u - 1] + sum[j][2] - sum[v][2], dp[i][j][u]);///选j
if (i == j)
for (int v = 0;v < i;v++) dp[i][j][u] = max(dp[v][v][u - 1] + sum[i][1] - sum[v][1] + sum[j][2] - sum[v][2], dp[i][j][u]);///选i和j相连 }
}
}
cout << dp[n][n][k] << '\n';
return 0;
}

NC20242 [SCOI2005]最大子矩阵的更多相关文章

  1. BZOJ 1084: [SCOI2005]最大子矩阵 DP

    1084: [SCOI2005]最大子矩阵 题目连接: http://www.lydsy.com/JudgeOnline/problem.php?id=1084 Description 这里有一个n* ...

  2. 1084: [SCOI2005]最大子矩阵

    1084: [SCOI2005]最大子矩阵 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1325  Solved: 670[Submit][Stat ...

  3. bzoj千题计划198:bzoj1084: [SCOI2005]最大子矩阵

    http://www.lydsy.com/JudgeOnline/problem.php?id=1084 m=1: dp[i][j] 前i个数,选了j个矩阵的最大和 第i个不选:由dp[i-1][j] ...

  4. 【BZOJ 1084】 1084: [SCOI2005]最大子矩阵 (DP)

    1084: [SCOI2005]最大子矩阵 Description 这里有一个n*m的矩阵,请你选出其中k个子矩阵,使得这个k个子矩阵分值之和最大.注意:选出的k个子矩阵不能相互重叠. Input 第 ...

  5. BZOJ(6) 1084: [SCOI2005]最大子矩阵

    1084: [SCOI2005]最大子矩阵 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 3566  Solved: 1785[Submit][Sta ...

  6. [Luogu 2331] [SCOI2005]最大子矩阵

    [Luogu 2331] [SCOI2005]最大子矩阵 题目描述 这里有一个n*m的矩阵,请你选出其中k个子矩阵,使得这个k个子矩阵分值之和最大.注意:选出的k个子矩阵不能相互重叠. 输入输出格式 ...

  7. 洛谷P2331 [SCOI2005]最大子矩阵 DP

    P2331 [SCOI2005]最大子矩阵 题意 : 这里有一个n*m的矩阵,请你选出其中k个子矩阵,使得这个k个子矩阵分值之和最大.注意:选出的k个子矩阵不能相互重叠. 第一行为n,m,k(1≤n≤ ...

  8. [bzoj1084][SCOI2005]最大子矩阵_动态规划_伪·轮廓线dp

    最大子矩阵 bzoj-1084 SCOI-2005 题目大意:给定一个n*m的矩阵,请你选出k个互不重叠的子矩阵使得它们的权值和最大. 注释:$1\le n \le 100$,$1\le m\le 2 ...

  9. [SCOI2005]最大子矩阵

    题目描述 这里有一个n*m的矩阵,请你选出其中k个子矩阵,使得这个k个子矩阵分值之和最大.注意:选出的k个子矩阵不能相互重叠. 输入输出格式 输入格式: 第一行为n,m,k(1≤n≤100,1≤m≤2 ...

随机推荐

  1. MTK 虚拟 sensor bring up (pick up) sensor1.0

    pick up bring up sensor1.0 1.pick up对比 2.SCP 1.添加驱动文件 2.添加编译环境(打开开关) 注:编译过程中如果显示内存不够 3.修改底层数据上报方式 3. ...

  2. 0-1knapsack

    Python 实现0-1背包问题(回溯法) 题目 解题思路 回溯法:为了避免生成那些不可能产生最佳解的问题状态,要不断地利用限界函数(bounding function)来处死那些实际上不可能产生所需 ...

  3. ESXI系列问题整理以及记录——使用SSH为设备打VIB驱动包,同时提供一种对于ESXI不兼容螃蟹网卡(Realtek 瑞昱)的问题解决思路

    对于ESXI不兼容螃蟹网卡的问题,这里建议购买一张博通的低端单口千兆网卡,先使用博通网卡完成系统部署,再按照下文方法添加螃蟹网卡的VIB驱动,最后拆除博通网卡. 螃蟹网卡VIB驱动包下载地址:http ...

  4. 在生产中部署ML前需要了解的事

    在生产中部署ML前需要了解的事 译自:What You Should Know before Deploying ML in Production MLOps的必要性 MLOps之所以重要,有几个原因 ...

  5. shell 问题记录

    工作中写了个 RestAPI 接口,然后想通过 crontab 任务,去定时调用接口.发现去拼接 post 请求真的不容易.对于单引号,双引号的使用.很懵,示例代码如下:对于 '$line' 处,单引 ...

  6. 1.2 操作系统的第二个功能——并发功能 -《zobolの操作系统学习札记》

    1.2 操作系统的第二个功能--并发功能 目录 1.2 操作系统的第二个功能--并发功能 问1:什么是并发功能?并发功能是必要的吗? 问2:并发功能必须要求拥有多核CPU吗? 问3:多核CPU和单核C ...

  7. 根据数据中的key获取value值

    一.测试数据准备 List<Map<String, String>> result = new ArrayList();Map<String, String> ma ...

  8. linux系统健康检查脚本

    #!/bin/bash echo "You are logged in as `whoami`"; if [ `whoami` != root ]; then echo " ...

  9. Vue的基础语法

    前言 Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架.与其它大型框架不同的是, Vue 被设计为可以自底向上逐层应用.Vue 的核心库只关注视图层,不仅易于上手, ...

  10. C++ 练气期之一文看懂字符串

    C++ 练气期之细聊字符串 1. 概念 程序不仅仅用于数字计算,现代企业级项目中更多流转着充满了烟火气的人间话语.这些话语,在计算机语言称为字符串. 从字面上理解字符串,类似于用一根竹签串起了很多字符 ...