[ 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< ...
随机推荐
- [luoguP2701] [USACO5.3]巨大的牛棚Big Barn(DP)
传送门 经典问题. 找出最大的不包含 1 的正方形. f[i][j] 表示 以 (i,j) 结尾的最大的不包含 1 的正方形 f[i][j] = min(f[i - 1][j], f[i][j - 1 ...
- 【网络流24题】最长k可重区间集问题(费用流)
[网络流24题]最长k可重区间集问题 [问题分析] 最大权不相交路径问题,可以用最大费用最大流解决. [建模方法] 方法1 按左端点排序所有区间,把每个区间拆分看做两个顶点<i.a>< ...
- C++ - 一个构造函数调用构造函数的问题
今天做C++的实验,题目是写一个二维点的类,然后让一个三维点的类继承它然后扩展.题目是一般学面向对象语言的常用例子. 然后遇到一个这样的问题:之前用Java的时候写构造方法的时 ...
- CF899F. Letters Removing
给一个字符串支持以下操作:区间删除某个特定字符.最后输出字符串.n,m<=200000. 这题我居然不会可以回家了.. 首先,单点删除,选个平衡树比如set. 然后,他给的下标是会随删除操作变化 ...
- jQuery通过event获取点击事件的事件对象
要想搞明白js的事件机制,必须搞清楚几个概念:事件对象,事件源,还有事件流 事件对象: 当事件发生时会产生事件对象,事件对象的作用是用来记录“事件发生是一些相关的信息.注意事件对象只有在事件发生时才会 ...
- 夜话JAVA设计模式之适配器模式(adapter pattern)
适配器模式:将一个类的接口,转换成客户期望的另一个接口,让不兼容的接口变成兼容. 1.类适配器模式:通过多重继承来实现适配器功能.多重继承就是先继承要转换的实现类,再实现被转换的接口. 2.对象适配器 ...
- [poj1678]I Love this Game!_博弈论
I Love this Game! 题目大意:题目链接 注释:略. 想法: 开始的时候以为没法dp,结果...:a>0啊! 所以可以直接dp了啊! 状态:dp[i]表示先手选了a[i]的状态. ...
- Junit4使用总结
常用注解 @Before:初始化方法,在任何一个测试方法执行之前,必须执行的代码. @After:释放资源,在任何一个测试方法执行之后,需要进行的收尾工作. @Test:测试方法,表明这是一个测试 ...
- CHAPTER 1 Architectural Overview of Oracle Database 11g
Which SGA structures are required, and which are optional? The database buffer cache, log buffer, an ...
- c++面试问题的几个方向
1 关于多态,面向对象的几个要点作为面向对象的程序员,这个问题是必须要弄清楚的,网上.教科书上都是标准答案,关键是理解内涵哦. 2 关于虚函数表和RTTI 这个Inside C++ Object Mo ...