[ 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< ...
随机推荐
- Mysql学习总结(42)——MySql常用脚本大全
备份 (所有) C:\Program Files\MySQL\MySQL Server 5.6\bin>mysqldump --no-defaults -hlocalhost -P3306 -u ...
- poj 2823 二分法+单调队列
#include<stdio.h> #include<string.h> #define N 1100000 int a[N]; int fmin[N],fmax[N]; i ...
- NOIP1999 邮票面值设计
题目描述 Description 给定一个信封,最多只允许粘贴N张邮票,计算在给定K(N+K≤40)种邮票的情况下(假定所有的邮票数量都足够),如何设计邮票的面值,能得到最大值MAX,使在1-MAX之 ...
- - > 贪心基础入门讲解五——任务执行顺序
分析: 本题可以抽象成,从一个整数开始,每次减去a,再加上b (a,b都是正数),要求每次操作都不产生负数. 针对本题a[i] = R[i], b[i] = R[i] – O[i],注意O[i] &l ...
- Android推断屏幕锁屏的方法总结
转载请注明:http://blog.csdn.net/heroxuetao/article/details/24639203 因为做一个项目,须要推断屏幕是否锁屏,发现网上方法非常多.可是比較杂.如今 ...
- Leetcode题解(5):L58/Length of Last Word
L58: Length of Last Word Given a string s consists of upper/lower-case alphabets and empty space cha ...
- Qt学习之QListWidget删除Item
将QListWidgetItem从QListWidget列表中删除有两种方法能够做到.但也要依据自己的须要进行选择. 第一种是 QListWidgetItem *takeItem(int row); ...
- 5分钟Serverless实践:构建无服务器的图片分类系统
前言 在过去“5分钟Serverless实践”系列文章中,我们介绍了如何构建无服务器API和Web应用,从本质上来说,它们都属于基于APIG触发器对外提供一个无服务器API的场景.现在本文将介绍一种新 ...
- 关于C语言指针的一些新认识(2)
在使用C语言编程的过程中,遇到了很多关于指针使用的小问题,这里总结一下就当做是编程的小技巧啦 Q1. 如何用printf( )输出指针 这个问题相当于如何用printf( )输出地址,答案是:用"%p ...
- B. Case of Fake Numbers( Codeforces Round #310 (Div. 2) 简单题)
B. Case of Fake Numbers time limit per test 2 seconds memory limit per test 256 megabytes input stan ...