P2331 [SCOI2005]最大子矩阵
P2331 [SCOI2005]最大子矩阵
0x01 题意
这里有一个n*m的矩阵,请你选出其中k个子矩阵,使得这个k个子矩阵分值之和最大。注意:选出的k个子矩阵不能相互重叠。
其中\(1\le n\le 100,1\le m\le 2,1\le k\le 10.\)
0x02 解
\(m\)只有\(1\)和\(2\)两种取值,所以直接讨论就好
\(m=1\)时:
是前\(k\)个最大连续字段和
定义\(f[i][j]\)为前\(i\)个数中取出\(j\)个矩形的最大和
则有:
\[\begin{aligned}
&选:f[i][j]=max(f[k-1][j-1]+s[i]-s[k-1])\\
&不选:f[i][j]=max(f[i][j],f[i-1][j])
\end{aligned}
\]
\(m=2\)时:
定义\(f[i][j][p]\)为第一列选到第\(i\)个数,第二列选到第\(j\)个数时,总共\(k\)个子矩阵的最大和
则有:
\[\begin{aligned}
&不选:f[i][j][p]=max(f[i-1][j][p],f[i][j-1][p])\\
&选第一列:f[i][j][p]=max(f[k-1][j][p-1]+s1[i]-s1[k-1])\\
&选第二列:f[i][j][p]=max(f[i][k-1][p-1]+s2[j]-s2[k-1])\\
&选两列:if(i==j) f[i][j][p]=max(f[k-1][k-1][p-1]+s1[i]+s2[i]-s1[k-1]-s2[k-1])
\end{aligned}
\]
注意\(k\)的边界
0x03 码
#include<bits/stdc++.h>
using namespace std;
const int N =110;
int n,m,k,s1[N],s2[N],f[N][N][N];
int main(){
memset(f,0,sizeof f);
memset(s1,0,sizeof s1);
memset(s2,0,sizeof s2);
scanf("%d%d%d",&n,&m,&k);
int o;
for(int i=1;i<=n;i++){
if(m==1) scanf("%d",&o),s1[i]=s1[i-1]+o;
else{
scanf("%d",&o);
s1[i]=s1[i-1]+o;
scanf("%d",&o);
s2[i]=s2[i-1]+o;
}
}
if(m==1){
for(int p=1;p<=k;p++){
for(int i=1;i<=n;i++){
f[i][p][0]=max(f[i][p][0],f[i-1][p][0]);
for(int j=1;j<=i;j++) f[i][p][0]=max(f[i][p][0],f[j-1][p-1][0]+s1[i]-s1[j-1]);
}
}
printf("%d\n",f[n][k][0]);
}else{
for(int p=1;p<=k;p++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
f[i][j][p]=max(f[i-1][j][p],f[i][j-1][p]);
for(int r=1;r<=i;r++) f[i][j][p]=max(f[i][j][p],f[r-1][j][p-1]+s1[i]-s1[r-1]);
for(int r=1;r<=j;r++) f[i][j][p]=max(f[i][j][p],f[i][r-1][p-1]+s2[j]-s2[r-1]);
if(i==j) for(int r=1;r<=i;r++) f[i][j][p]=max(f[i][j][p],f[r-1][r-1][p-1]+s1[i]+s2[j]-s1[r-1]-s2[r-1]);
}
}
}
printf("%d\n",f[n][n][k]);
}
return 0;
}