[ SCOI 2005 ] 最大子矩阵
\(\\\)
\(Description\)
给出一个\(N\times M\)的有权矩阵,选出其中\(K\)个互不重叠的子矩阵,使得这\(K\)个子矩阵的权值和最大。
- \(N\in [1,100]\),\(M\in \{1,2\}\),\(K\in [1,10]\)
\(\\\)
\(Solution\)
对于\(M=1\)的情况,矩阵是一个长为\(N\)的数列,问题变为\(K\)段最大子段和,可以参考:最大子段和系列问题。
对于\(M=2\)的情况,沿用上一情况的做法,设状态\(f[i][j][S]\)表示当前处理到第\(i\)行,已经选了\(j\)个子矩阵,本行选则方式为\(S\)的方案数。
分析情况可知,\(S\)有一下五种:
- \(0\):两个位置都不选
- \(1\):只选左边的元素
- \(2\):只选右边的元素
- \(3\):两个都选,放在一个矩形里
- \(4\):两个都选,放在两个矩形里
对五种状态分别讨论转移即可:
- \(0\)状态无需考虑任何限制,直接从上一行的五种状态转移:\(\begin{align}f[i][j][0]=max\{f[i-1][j][0/1/2/3/4]\}\end{align}\)
- \(1\)状态只能从\(1\)状态和\(4\)状态直接继承,其他都得从上一个矩形转移:\(\begin{align}f[i][j][1]=a[i][0]+max\{f[i-1][j-1][0/2/3],f[i-1][j][1/4]\}\end{align}\)
- \(2\)状态只能从\(2\)状态和\(4\)状态直接转移,其他都得从上一个矩形转移:\(\begin{align}f[i][j][2]=a[i][1]+max\{f[i-1][j-1][0/1/3],f[i-1][j][2/4]\}\end{align}\)
- \(3\)状态只能从\(3\)状态直接转移,定义\(s[i]=a[i][0]+a[i][1]\):\(\begin{align}f[i][j][3]=s[i]+max\{f[i-1][j-1][0/1/2/4],f[i-1][j][3]\}\end{align}\)
- \(4\)状态只能直接从\(4\)状态转移,但是可以利用\(1\)状态和\(2\)状态的矩阵:\(\begin{align}f[i][j][4]=s[i]+max\{f[i-1][j-2][0/3],f[i-1][j-1][1/2],f[i-1][j][4]\}\end{align}\)
需要注意的是,初始化只有所有的\(0\)状态为\(0\),其他应该是\(-\infty\),防止一些转移的初始状态不存在。
\(\\\)
\(Code\)
#include<cmath>
#include<cctype>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define N 110
#define K 15
#define R register
#define gc getchar
using namespace std;
inline int rd(){
int x=0; bool f=0; char c=gc();
while(!isdigit(c)){if(c=='-')f=1;c=gc();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
return f?-x:x;
}
int n,m,k,a[N][2],f[N][K][5];
inline void work1(){
for(R int i=1;i<=n;++i) a[i][0]=rd();
for(R int i=1;i<=n;++i)
for(R int j=1;j<=min(i,k);++j){
f[i][j][0]=max(f[i-1][j][0],f[i-1][j][1]);
f[i][j][1]=a[i][0]+max(f[i-1][j][1],max(f[i-1][j-1][0],f[i-1][j-1][1]));
}
printf("%d\n",max(f[n][k][1],f[n][k][0]));
};
inline int mx(int a,int b,int c,int d,int e){
return max(max(a,b),max(max(c,d),e));
}
inline void work2(){
memset(f,0xcf,sizeof(f));
for(R int i=0;i<=n;++i)
for(R int j=0;j<=k;++j) f[i][j][0]=0;
for(R int i=1;i<=n;++i){a[i][0]=rd();a[i][1]=rd();}
for(R int i=1;i<=n;++i)
for(R int j=1;j<=k;++j){
f[i][j][0]=mx(f[i-1][j][0],f[i-1][j][1],f[i-1][j][2],f[i-1][j][3],f[i-1][j][4]);
f[i][j][1]=a[i][0]+mx(f[i-1][j][1],f[i-1][j][4],f[i-1][j-1][0],f[i-1][j-1][2],f[i-1][j-1][3]);
f[i][j][2]=a[i][1]+mx(f[i-1][j][2],f[i-1][j][4],f[i-1][j-1][0],f[i-1][j-1][1],f[i-1][j-1][3]);
f[i][j][3]=a[i][0]+a[i][1]+mx(f[i-1][j][3],f[i-1][j-1][0],f[i-1][j-1][1],f[i-1][j-1][2],f[i-1][j-1][4]);
f[i][j][4]=a[i][0]+a[i][1]+max(f[i-1][j][4],max(f[i-1][j-1][1],f[i-1][j-1][2]));
if(j>=2) f[i][j][4]=max(f[i][j][4],a[i][0]+a[i][1]+max(f[i-1][j-2][0],f[i-1][j-2][3]));
}
printf("%d\n",mx(f[n][k][0],f[n][k][1],f[n][k][2],f[n][k][3],f[n][k][4]));
};
int main(){
n=rd(); m=rd(); k=rd();
(m==1)?work1():work2();
return 0;
}
[ SCOI 2005 ] 最大子矩阵的更多相关文章
- BZOJ 1084 (SCOI 2005) 最大子矩阵
1084: [SCOI2005]最大子矩阵 Time Limit: 10 Sec Memory Limit: 162 MB Submit: 3560 Solved: 1779 [Submit][Sta ...
- 【SCOI 2005】 最大子矩阵
[题目链接] 点击打开链接 [算法] 动态规划 我们发现,M只有两种取值,1和2,那么,只需分类讨论即可 当M = 1时,其实这个问题就成了就最大连续子段和的问题,只不过要选K段而已 用f[i][j] ...
- 【BZOJ 1087】【SCOI 2005】互不侵犯King
http://www.lydsy.com/JudgeOnline/problem.php?id=1087 很简单的状压,需要预处理,我两个状态可不可以挨着的预处理出错WA了好几次. 这个位运算预处理好 ...
- [SCOI 2005]王室联邦
Description “余”人国的国王想重新编制他的国家.他想把他的国家划分成若干个省,每个省都由他们王室联邦的一个成员来管理.他的国家有n个城市,编号为1..n.一些城市之间有道路相连,任意两个不 ...
- 解题:SCOI 2005 骑士精神
题面 我把这个当做IDA*的模板题的说,说说我个人对IDA*的理解 IDA*是一个DFS,和A*一样,它也有一个乐观的估价函数.这里这个估价函数是用来限制状态的扩展的,如果当前代价加上乐观的估计都无法 ...
- 【题解】互不侵犯 SCOI 2005 BZOJ 1087 插头dp
以前没学插头dp的时候觉得这题贼难,根本不会做,学了才发现原来是一裸题. 用二进制表示以前的格子的状态,0表示没放国王,1表示放了国王. 假设当前位置为(x,y),需要记录的是(x-1,y-1)至(x ...
- 【SCOI 2005】 扫雷
[题目链接] 点击打开链接 [算法] 只要第一行第一个数确定了,后面的数也都确定了 递推两遍即可 [代码] #include<bits/stdc++.h> using namespace ...
- 【SCOI 2005】 繁忙的都市
[题目链接] 点击打开链接 [算法] 题目描述比较繁琐,但细心观察后,发现其实就是用kruskal算法求最小生成树 [代码] #include<bits/stdc++.h> using n ...
- 【SCOI 2005】 互不侵犯
[题目链接] 点击打开链接 [算法] 和HDU2167类似 先搜出一行内符合的状态,然后,f[i][j][k]表示第i行,第j种状态,放了k个,合法的方案,DP即可 [代码] #include< ...
随机推荐
- Spring mvc+Easyui遇到的几个问题
简单的一个数据表的增删查改的总体界面的展示效果例如以下图: 1.datagrid数据载入问题 datagrid通过url请求后台数据,总记录数和数据行的属性是固定死的.数据行是rows,总记录数为to ...
- PAT Broken Keyboard (20)
题目描写叙述 On a broken keyboard, some of the keys are worn out. So when you type some sentences, the cha ...
- 【大话QT之十四】QT实现多语言切换
功能需求: 网盘client要可以实现多国语言的切换,第一版要支持中.英文的切换. 在实现过程中感觉QT对多国语言的支持还是非常不错的.制作多语言包非常方便.切换的逻辑也非常easy. 以下就来看一下 ...
- iOS开发之剖析"秘密"App内容页面效果(一)
近期在玩"秘密",发现点击主界面的Cell进去后的页面效果不错,就写了个Demo来演示下. 它主要效果:下拉头部视图放大,上拉视图模糊并且到一定位置固定不动,其它Cell能够继续上 ...
- Oracle Temp 表空间切换
一.TEMP表空间作用 暂时表空间主要用途是在数据库进行排序运算.管理索引.訪问视图等操作时提供暂时的运算空间,当运算完毕之后系统会自己主动清理.当 oracle 里须要用到 sort 的时候. PG ...
- NodeJS经常使用模块收集
收集了NodeJS开发中经常使用的一些模块. MVC框架 - Express Express 是轻量灵活的Nodejs Web应用框架.它能够高速地搭建站点. Express框架建立在Nodejs内置 ...
- LeetCode 709. To Lower Case (转换成小写字母)
题目标签:String 题目让我们把大写字母转换成小写,只要遇到的是大写字母,把它 + 32 变成 小写就可以了. Java Solution: Runtime beats 100.00% 完成日期: ...
- 数据库html 数据的分句
Python 中文分句 - CSDN博客 https://blog.csdn.net/laoyaotask/article/details/9260263 # 设置分句的标志符号:可以根据实际需要进行 ...
- mp3播放时间
import os os_sep = os.sep this_file_abspath = os.path.abspath(__file__) this_file_dirname, this_file ...
- 如何利用UDP协议封装一个数据包
在如何封装一个数据包上,是一个非常细致的问题,而利用UDP协议来封装的话,是比较简单,让我们一步步来分析典型的TCP/IP协议.一般来说一个典型的一个数据包,包括以太网MAC头+网络层IP数据头+传输 ...