\(\\\)

\(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 ] 最大子矩阵的更多相关文章

  1. BZOJ 1084 (SCOI 2005) 最大子矩阵

    1084: [SCOI2005]最大子矩阵 Time Limit: 10 Sec Memory Limit: 162 MB Submit: 3560 Solved: 1779 [Submit][Sta ...

  2. 【SCOI 2005】 最大子矩阵

    [题目链接] 点击打开链接 [算法] 动态规划 我们发现,M只有两种取值,1和2,那么,只需分类讨论即可 当M = 1时,其实这个问题就成了就最大连续子段和的问题,只不过要选K段而已 用f[i][j] ...

  3. 【BZOJ 1087】【SCOI 2005】互不侵犯King

    http://www.lydsy.com/JudgeOnline/problem.php?id=1087 很简单的状压,需要预处理,我两个状态可不可以挨着的预处理出错WA了好几次. 这个位运算预处理好 ...

  4. [SCOI 2005]王室联邦

    Description “余”人国的国王想重新编制他的国家.他想把他的国家划分成若干个省,每个省都由他们王室联邦的一个成员来管理.他的国家有n个城市,编号为1..n.一些城市之间有道路相连,任意两个不 ...

  5. 解题:SCOI 2005 骑士精神

    题面 我把这个当做IDA*的模板题的说,说说我个人对IDA*的理解 IDA*是一个DFS,和A*一样,它也有一个乐观的估价函数.这里这个估价函数是用来限制状态的扩展的,如果当前代价加上乐观的估计都无法 ...

  6. 【题解】互不侵犯 SCOI 2005 BZOJ 1087 插头dp

    以前没学插头dp的时候觉得这题贼难,根本不会做,学了才发现原来是一裸题. 用二进制表示以前的格子的状态,0表示没放国王,1表示放了国王. 假设当前位置为(x,y),需要记录的是(x-1,y-1)至(x ...

  7. 【SCOI 2005】 扫雷

    [题目链接] 点击打开链接 [算法] 只要第一行第一个数确定了,后面的数也都确定了 递推两遍即可 [代码] #include<bits/stdc++.h> using namespace ...

  8. 【SCOI 2005】 繁忙的都市

    [题目链接] 点击打开链接 [算法] 题目描述比较繁琐,但细心观察后,发现其实就是用kruskal算法求最小生成树 [代码] #include<bits/stdc++.h> using n ...

  9. 【SCOI 2005】 互不侵犯

    [题目链接] 点击打开链接 [算法] 和HDU2167类似 先搜出一行内符合的状态,然后,f[i][j][k]表示第i行,第j种状态,放了k个,合法的方案,DP即可 [代码] #include< ...

随机推荐

  1. [K/3Cloud]如何解决K3Cloud 2.0审批流提交时报“队列不存在,或您没有足够的权限执行该操……

    按照图上的操作即可解决不可提交的问题,但如果应用服务器是部署在域环境下,应该不会出错,这是微软support上说的

  2. DJANGO中正规的建立与USER外键的方式

    以前都是直接与user 最近看书,上说settings.AUTH_USER_MODEL,这样好些...是为记. from django.db import models from django.con ...

  3. 对象和变量的并发访问synchronized解析以及死锁分析排查

    一.synchronized java并发编程中存在“非线程安全"问题.“非线程安全"是指发生在多个线程对同一个对象中的实例变量并发访问时,产生的”脏读“现象,使用synchron ...

  4. Ubuntu 16.04监控网络带宽软件

    1.系统监控器已经自带了默认的监控功能,包括CPU.内存.带宽.进程等,但带宽的一些详情不能显示出来. 2.使用top命令进行监控进程 sudo top 3.安装Indicator-sysmonito ...

  5. 演练:使用VS2010 C# 创作简单的多线程组件

    BackgroundWorker 组件取代了 System.Threading 命名空间并添加了功能:但是,可以选择保留 System.Threading 命名空间以实现向后兼容并供将来使用.有关更多 ...

  6. 【转】gcov lcov 覆盖c/c++项目入门

    原文: http://www.cnblogs.com/turtle-fly/archive/2013/01/09/2851474.html ------------------------------ ...

  7. JavaSE学习笔记--Item1 注解Annotation

    从 JDK 5.0 開始, Java 添加了对元数据(MetaData) 的支持, 也就是 Annotation(注解). 什么是Annotation,以及注解的作用? 三个主要的 Annotatio ...

  8. 数学之路-python计算实战(1)-ubuntu安装pypy

    Get the source code. The following packages contain the source at the same revision as the above bin ...

  9. SOJ.Output the Yanghui triangel

    Output the Yanghui triangel     总提交数量: 225 通过数量: 59                 时间限制:1秒    内存限制:256兆 题目描写叙述 Writ ...

  10. 【Aladdin Unity3D Shader编程】之二 光照模型(一)

    光照模型 光照模型就是一个公式,使用这个公式来计算在某个点的光照效果. 在标准光照模型里面,我们把进入摄像机的光分为下面四个部分: 自发光 类似生活中的萤火虫等自己能够发光 高光反射 类似生活中的镜子 ...