1084: [SCOI2005]最大子矩阵
Description
这里有一个n*m的矩阵,请你选出其中k个子矩阵,使得这个k个子矩阵分值之和最大。注意:选出的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
【解题报告】
题解来自http://blog.csdn.net/zz_ylolita/article/details/50647536
注意到m=1或者2,当m=1时,是普通的最大连续字段和,只不过是k个:
设f[i][j]表示前i个数中取出j个矩形的最大和
选:f[i][j]=max{f[i1][j-1]+s[i]-s[i1-1]}
不选:f[i][j]=max(f[i][j],f[i-1][j])
复杂度O(n^2*K)
当m=2时,设f[i][j][k]表示第一列选到第i个数,第二列选到第j个数时,总共k个子矩形的答案
转移有4种情况
当这一位什么都不做的时候:f[i][j][k]=max(f[i-1][j][k],f[i][j-1][k]) //这里有点像最长公共子序列的转移,也是背包问题
当仅选取第一列的某段区间时:f[i][j][k]=max(f[i1][j][k-1]+sum[i][1]-sum[i1-1][1]) 1<=i1<=i-1
当仅选取第二列的某段区间时:f[i][j][k]=max(f[i][j1][k-1]+sum[j][2]-sum[j1-1][2]) 1<=j1<=j-1
当i==j时,可以选取两列一起的矩形:f[i][j][k]=max(f[i1][i1][k]+sum[i][1]+sum[i][2]-sum[i1-1][1]-sum[i1-1][2])
最后所有情况取max
复杂度O(n^3*K)
代码如下:
/**************************************************************
Problem: 1084
User: onepointo
Language: C++
Result: Accepted
Time:80 ms
Memory:1536 kb
****************************************************************/
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 110
#define inf 0x3f3f3f3f
int n,m,K;
int f[N][N][15],s[N][15];
int main()
{
scanf("%d%d%d",&n,&m,&K);
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
{
scanf("%d",&s[i][j]);
s[i][j]+=s[i-1][j];
}
if(m==1)
{
for(int i=1;i<=n;++i)
for(int k=1;k<=K;++k)
{
f[i][0][k]=f[i-1][0][k];
for(int j=k-1;j<i;++j)
{
f[i][0][k]=max(f[j][0][k-1]+s[i][1]-s[j][1],f[i][0][k]);
}
}
printf("%d\n",f[n][0][K]);
}
if(m==2)
{
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
for(int k=1;k<=K;++k)
{
f[i][j][k]=max(f[i-1][j][k],f[i][j-1][k]);
for(int u=0;u<i;u++) f[i][j][k]=max(f[i][j][k],f[u][j][k-1]+s[i][1]-s[u][1]);
for(int u=0;u<j;u++) f[i][j][k]=max(f[i][j][k],f[i][u][k-1]+s[j][2]-s[u][2]);
if(i==j) for(int u=0;u<i;u++) f[i][j][k]=max(f[i][j][k],f[u][u][k-1]+s[i][1]-s[u][1]+s[i][2]-s[u][2]);
}
printf("%d\n",f[n][n][K]);
}
return 0;
}