题目链接

题目

题目描述

这里有一个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. 【Tools】JAR怀旧模拟器推荐

    前段时间突然很怀念小时候玩的仙剑奇侠传,于是在网上各种找,功夫不负有心人,让我找到并且通关了.相信也有人需要.下面是截图. 下载地址:https://www.lanzous.com/ialmayh  

  2. 前端 关于请求地址时出现乱码, 出现%E2%80%8B的问题

    做项目时,添加了新的一个接口,习惯性地复制了接口下来.然后测试发现 请求时自动添加 了几个%E2%80%8B这种乱码. 问题原因: 我输出请求地址时也是正确的,是因为复制过来的接口地址会有零宽空格 解 ...

  3. 用STM32玩OLED(显示文字、图片、动图gif等)

    目录 用STM32玩OLED(显示文字.图片.动图gif等) 1. 显示字符串 2. 显示中文 3. 显示图片 4. 显示动图 5. 总结测试 用STM32玩OLED(显示文字.图片.动图gif等) ...

  4. 代码模板整理(0):先水一波a+b

    梦开始的地方 "Hello World!" #include<bits/stdc++.h> using namespace std; int main(){ cout& ...

  5. Number.prototype.toString()方法

    Number.prototype.toString(radix)方法返回指定基数对应Number的字符串值 radix可选参数,值范围为2~36,转化基数,如果未指定,默认值为10,如果radix值不 ...

  6. Python双人五子棋

    这篇文章旨在介绍一个双人的五子棋程序.再次重申,本人不擅长对代码的可读性进行优化,所以可能有些杂乱(在所难免). 先瞅一眼效果图: 请注意,这个棋子--是这么圆润立体!本程序不需任何素材图片,完全用代 ...

  7. UiPath官网认证中文教程

    RPA之家公众号:RPA之家 RPA之家官网:http://rpazj.com 斗鱼直播:http://www.douyu.com/rpazj UiPath中文社区QQ群:465630324 RPA& ...

  8. lvm逻辑卷创建及使用

    创建逻辑卷 pvcreate /dev/md0 pvs 查看创建的pv组 pvdisplay /dev/md0 查看磁盘详细信息 添加vg组: 创建vg组: vgcreate vg1 /dev/md0 ...

  9. 超 Nice 的表格响应式布局小技巧

    今天,遇到了一个很有意思的问题,一名群友问我,仅仅使用 CSS,能否实现这样一种响应式的布局效果: 简单解析一下效果: 在屏幕视口较为宽时,表现为一个整体 Table 的样式 而当屏幕视口宽度较小时, ...

  10. Linux for CentOS 下的 keepalived 安装与卸载以及相关命令操作之详细教程

    百度百科解释: keepalived 是一个类似于 layer3, 4 & 7 交换机制的软件,也就是我们平时说的第 3 层.第 4 层和第 7 层交换.Keepalived 的作用是检测 w ...