Description
这里有一个n*m的矩阵,请你选出其中k个子矩阵,使得这个k个子矩阵分值之和最大。注意:选出的k个子矩阵不能相互重叠。
Sample Input
3 2 2
1 -3
2 3
-2 3
Sample Output
9
这题是DP,因为m很小,只有1和2。
首先设
sum[i][1]=sum[i-1][1]+sum[i][1]
sum[i][2]=sum[i-1][2]+sum[i][2]
所以可以分情况讨论,m=1时:
设DP[i][kk]为1~i行分成kk个矩阵,
DP方程是:DP[i][kk]=max(DP[i][kk],DP[j][kk-1]+sum[i]-sum[j]);
当m=2时:
设DP[i][j][kk]为第1列1~i行和第二列1~j行分成kk个矩阵。
则枚举ii(0~i-1),ii~i为一个新的矩阵,DP方程为:f[i][j][kk]=max(f[i][j][kk],f[ii][j][kk-1]+sum[i][1]-sum[ii][1]);
则枚举jj(0~j-1),jj~j为一个新的矩阵,DP方程为:f[i][j][kk]=_max(f[i][j][kk],f[i][jj][kk-1]+sum[j][2]-sum[jj][2]);
若i=j,还可以将两列看成一个大矩阵,则枚举hh(0~i-1),DP方程为:f[i][j][kk]=max(f[i][j][kk],f[hh][hh][kk-1]+sum[i][1]-sum[hh][1]+sum[j][2]-sum[hh][2]);
#include<cstdio>
#include<cstring>
using namespace std;
int f[110][110][11],sum[110][3];
int _max(int x,int y){return x>y?x:y;}
int main()
{
int n,m,k;scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
scanf("%d",&sum[i][j]);
sum[i][j]+=sum[i-1][j];
}
}
if(m==1)
{
for(int i=1;i<=n;i++)
{
for(int kk=1;kk<=k;kk++)
{
if(i==kk)f[i][0][kk]=sum[i][1];
else
{
f[i][0][kk]=f[i-1][0][kk];
for(int j=kk-1;j<i;j++)
{
f[i][0][kk]=_max(f[i][0][kk],f[j][0][kk-1]+sum[i][1]-sum[j][1]);
}
}
}
}
printf("%d\n",f[n][0][k]);
}
else
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
for(int kk=1;kk<=k;kk++)
{
f[i][j][kk]=_max(f[i-1][j][kk],f[i][j-1][kk]);
for(int ii=0;ii<i;ii++)f[i][j][kk]=_max(f[i][j][kk],f[ii][j][kk-1]+sum[i][1]-sum[ii][1]);
for(int jj=0;jj<j;jj++)f[i][j][kk]=_max(f[i][j][kk],f[i][jj][kk-1]+sum[j][2]-sum[jj][2]);
if(i==j)
{
for(int hh=0;hh<i;hh++)
{
f[i][j][kk]=_max(f[i][j][kk],f[hh][hh][kk-1]+sum[i][1]-sum[hh][1]+sum[j][2]-sum[hh][2]);
}
}
}
}
}
printf("%d\n",f[n][n][k]);
}
return 0;
}