Written with StackEdit.
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<bits/stdc++.h>
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;
}