博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
bzoj 1084 最大子矩阵
阅读量:4565 次
发布时间:2019-06-08

本文共 3805 字,大约阅读时间需要 12 分钟。

Written with .

Description

这里有一个\(n*m\)的矩阵,请你选出其中\(k\)个子矩阵,使得这个\(k\)个子矩阵分值之和最大.注意:选出的\(k\)个子矩阵不能相互重叠。

ps:这里的题意有些不明确...可以选空矩阵(最多选\(k\)个),不能重叠指的是不能有相交部分.

Input

第一行为\(n,m,k\)\(1≤n≤100,1≤m≤2,1≤k≤10\)),接下来\(n\)行描述矩阵每行中的每个元素的分值(分值的绝对值不超过\(32767\))。

Output

只有一行,为\(k\)个子矩阵分值之和最大为多少。

Sample Input

3 2 2

1 -3
2 3
-2 3

Sample Output

9

Hint

none.

Solution

  • 注意到只有\(m=1,m=2\)两种情况.
    • 对于\(m=1\)的情况,直接做一个最大字段和\(dp\)就可以了.
    • \(f[i][j][0/1]\)表示考虑前\(i\)个数,用了\(j\)段,第\(i\)个数选了/没选的答案.
  • 对于\(m=2\)的情况,与\(m=1\)类似,用\(f[i][j][k]\)表示考虑前\(i\)个数,用了\(j\)个矩形,而\(k\)用于表示第\(i\)行的选择情况.
  • 不妨令\(k=0\)表示这一行都没选.
  • \(k=1\)表示这一行只选了左边的数.
  • \(k=2\)表示这一行只选了右边的数.
  • 对于左右两个数都选的情况,注意到样例中第二行的\(2,3\)虽然同时被选到,但属于不同的子矩形,所以要对是否在同一个子矩形中进行区分.
  • \(k=3\)表示这一行同时选了左右两个数,且两个数属于相同的子矩形
  • \(k=4\)表示这一行同时选了左右两个数,且两个数属于不同的子矩形.
  • 在转移时分别判断能否和上一行的各个状态拼接上,就完成了状态转移.
  • 这样我们也不用特判\(m\)了,将\(m=1\)的时候看做第二列都是\(0\),一起处理.
  • 具体转移方程和细节参见代码.
#include
using namespace std;inline int read(){ int out=0,fh=1; char jp=getchar(); while ((jp>'9'||jp<'0')&&jp!='-') jp=getchar(); if (jp=='-') { fh=-1; jp=getchar(); } while (jp>='0'&&jp<='9') { out=out*10+jp-'0'; jp=getchar(); } return out*fh;}int n,m,k;const int MAXN=101;int a[MAXN][2];int f[MAXN][11][5];inline void upd(int &x,int y){ x=max(x,y);}void sub_line(){ int ans=0; for(int i=1;i<=n;++i) { for(int j=1;j<=k;++j) { f[i][j][0]=max(f[i-1][j][0],f[i-1][j][1]); f[i][j][1]=max(f[i-1][j-1][0]+a[i][1],f[i-1][j][1]+a[i][1]); upd(ans,f[i][j][0]); upd(ans,f[i][j][1]); } } printf("%d\n",ans);}void sub_martix(){ int ans=0; memset(f,-0x7f,sizeof f);//一定要加上这句话,否则有些矩阵当前权值和为负,为了和其他部分凑成矩形必须选上. f[0][0][0]=0; for(int i=1;i<=n;++i) { int x=a[i][1],y=a[i][2]; upd(f[i][0][0],f[i-1][0][0]); for(int j=1;j<=k;++j) { for(int p=0;p<5;++p)//last upd(f[i][j][0],f[i-1][j][p]); upd(f[i][j][1],f[i-1][j-1][0]+x); upd(f[i][j][1],f[i-1][j][1]+x); upd(f[i][j][1],f[i-1][j-1][2]+x); upd(f[i][j][1],f[i-1][j-1][3]+x); upd(f[i][j][1],f[i-1][j][4]+x); upd(f[i][j][2],f[i-1][j-1][0]+y); upd(f[i][j][2],f[i-1][j-1][1]+y); upd(f[i][j][2],f[i-1][j][2]+y); upd(f[i][j][2],f[i-1][j-1][3]+y); upd(f[i][j][2],f[i-1][j][4]+y); upd(f[i][j][3],f[i-1][j-1][0]+x+y); upd(f[i][j][3],f[i-1][j-1][1]+x+y); upd(f[i][j][3],f[i-1][j-1][2]+x+y); upd(f[i][j][3],f[i-1][j][3]+x+y); upd(f[i][j][3],f[i-1][j-1][4]+x+y); if(j>=2) upd(f[i][j][4],f[i-1][j-2][4]+x+y); if(j>=2) upd(f[i][j][4],f[i-1][j-2][0]+x+y); upd(f[i][j][4],f[i-1][j-1][1]+x+y); upd(f[i][j][4],f[i-1][j-1][2]+x+y); upd(f[i][j][4],f[i-1][j][4]+x+y); upd(ans,f[i][j][0]); upd(ans,f[i][j][1]); upd(ans,f[i][j][2]); upd(ans,f[i][j][3]); upd(ans,f[i][j][4]); } } printf("%d\n",ans);}int main(){ n=read(),m=read(),k=read(); for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) a[i][j]=read(); /*if(m==2) sub_martix(); else sub_line();*/ sub_martix(); return 0;}

转载于:https://www.cnblogs.com/jklover/p/9996092.html

你可能感兴趣的文章
算法第5章作业
查看>>
7.9 练习
查看>>
基于ArcGIS JS API的在线专题地图实现
查看>>
learnByWork
查看>>
Unity3D热更新之LuaFramework篇[04]--自定义UI监听方法
查看>>
lua 函数
查看>>
Git的基本命令
查看>>
四平方和
查看>>
第十八周 12.27-1.2
查看>>
C# IP地址字符串和数值转换
查看>>
TCHAR和CHAR类型的互转
查看>>
常用界面布局
查看>>
C语言—— for 循环
查看>>
IBM lotus9.0测试版即将公测
查看>>
xml常用方法
查看>>
Cube Stacking(并差集深度+结点个数)
查看>>
AndroidStudio3更改包名失败
查看>>
jq 删除数组中的元素
查看>>
添加按键事件处理及事件处理的参数传递
查看>>
js URL中文传参乱码
查看>>