题目链接

题目

题目描述

这里有一个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. 基于Proxmox平台搭建3D云教室

    背景 本文介绍了在 Proxmox VE 虚拟化平台上使用NVIDIA A16 GPU,开启vGPU特性,利用DoraCloud 搭建3D云教室的方案. Proxmox virtualization ...

  2. python操作MySQL与MySQL补充

    目录 python操作MySQL 基本使用 SQL注入问题 二次确认 视图 触发器 事务 存储过程 函数 流程控制 索引 练习 python操作MySQL python中支持操作MySQL的模块很多, ...

  3. JAVA - 启动线程有哪几种方式

    JAVA - 启动线程有哪几种方式 一.继承Thread类创建线程类 (1)定义Thread类的子类,并重写该类的run方法,该run方法的方法体就代表了线程要完成的任务.因此把run()方法称为执行 ...

  4. 【Java面试】请说一下ReentrantLock的实现原理?

    一个工作了3年的粉丝私信我,在面试的时候遇到了这样一个问题. "请说一下ReentrantLock的实现原理",他当时根据自己的理解零零散散的说了一些. 但是似乎没有说到关键点上, ...

  5. 七牛云创建存储空间并绑定自定义域名-https协议

    七牛云创建存储空间并绑定自定义域名-https协议 一.准备 0.绑定自定义域名的前提:你起码拥有过一个备案过的域名[一级域名] 1.在七牛云创建一个存储空间 2.存储空间绑定自定义域名(cdn加速) ...

  6. 【Redis】Redis Cluster初始化及PING消息的发送

    Cluster消息类型定义 #define CLUSTERMSG_TYPE_PING 0 /* Ping消息类型,节点间进行通信交换信息的消息 */ #define CLUSTERMSG_TYPE_P ...

  7. Ribbon的ServerStats引起内存泄露问题总结

    问题描述 服务运行一段时间之后,出现页面卡顿加载慢的问题,使用top命令查看了服务器的使用情况,发现CPU飙高,接着查看了该进程中每个线程的占用情况,发现导致CPU高的线程是JVM垃圾回收的线程,然后 ...

  8. JS:函数的形参与实参

    形参: 函数显式参数在函数定义时列出. 函数调用未传参时,参数会默认设置为: undefined. function fn(a,b,c){ //a,b,c为形参 //此时有一个隐式操作:var a,v ...

  9. CVPR2022 | 弱监督多标签分类中的损失问题

    前言 本文提出了一种新的弱监督多标签分类(WSML)方法,该方法拒绝或纠正大损失样本,以防止模型记忆有噪声的标签.由于没有繁重和复杂的组件,提出的方法在几个部分标签设置(包括Pascal VOC 20 ...

  10. Java 泛型中的通配符

    本文内容如下: 1. 什么是类型擦除 2.常用的 ?, T, E, K, V, N的含义 3.上界通配符 < ?extends E> 4.下界通配符 < ?super E> 5 ...