\(\\\)

\(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. nyoj 108 士兵杀敌(一)

    士兵杀敌(一) 时间限制:1000 ms  |  内存限制:65535 KB 难度:3   描述 南将军手下有N个士兵,分别编号1到N,这些士兵的杀敌数都是已知的. 小工是南将军手下的军师,南将军现在 ...

  2. hdu 5023 线段树延迟更新+状态压缩

    /* 线段树延迟更新+状态压缩 */ #include<stdio.h> #define N 1100000 struct node { int x,y,yanchi,sum; }a[N* ...

  3. 文化之旅 2012年NOIP全国联赛普及组

    时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题目描述 Description 有一位使者要游历各国,他每到一个国家,都能学到一种文化,但他不愿意学习任何一种文化超 ...

  4. codeforces gym 100357 H (DP 高精度)

    题目大意 有r*s张扑克牌,数字从1到 r,每种数字有s种颜色. 询问对于所有随机的d张牌,能选出c张组成顺子的概率和组成同花的概率. 解题分析 对于组成顺子的概率,令dp[i][j][k]表示一共选 ...

  5. Problem 2669

    Romantic Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total S ...

  6. 4、Java并发性和多线程-并发编程模型

    以下内容转自http://ifeve.com/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B%E6%A8%A1%E5%9E%8B/: 并发系统可以采用多种并发编程模型来实现. ...

  7. Linux进程空间分布 & 上下文

    Linux使用两级保护机制:0级供内核使用,3级供用户程序使用.从图中可以看出,每个进程有各自的私有用户空间(0~3G),这个空间对系统中的其他进程是不可见的.最高的1GB字节虚拟内核空间则为所有进程 ...

  8. POJ 1386 Play on Words(有向欧拉通路 连通图)

    题意  见下方中文翻译 每一个单词能够看成首尾两个字母相连的一条边  然后就是输入m条边  推断是否能构成有向欧拉通路了 有向图存在欧拉通路的充要条件: 1. 有向图的基图连通: 2. 全部点的出度和 ...

  9. Unity3d代码从Android/IOS迁移到WindowsPhone经验笔记

    [1搭建坏境] 推荐:Windows 8.1 Enterprise + Visual studio 2013(完整安装) PS: 假设要Visual Studio 2012,先安装VS再安装WP8/W ...

  10. HDU 5311 Hidden String (优美的暴力)

    Hidden String Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others) ...