题目描述:这里有一个n*m的矩阵,请你选出其中k个子矩阵,使得这个k个子矩阵分值之和最大。注意:选出的k个子矩阵不能相互重叠。(1≤n≤100,1≤m≤2,1≤k≤10)
解法:m为1或2,m=1时问题转化为经典DP问题,转移方程为dp[i][k]=max(dp[i-1][k],dp[i-选择区间长][k-1]+选择区间和),dp数组代表1到i之间取k个区间的最大值。类似的,m=2时使用三维数组,dp[i][j][k]=max(dp[i-1][j][k],dp[i][j-1][k],dp[i-l][j][k-1]+sum(l),dp[i][j-l][k-1]+sum(l)),另外再处理一下i=j的情况即可。
另外这题对于是否需要选满k个区间未解释清楚,这里给出的程序可以不选满,注意评测数据也避开了此问题。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n,m,k;
int map[300][3],dp[300][300][12];
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",&map[i][j]);
if(m==1){
memset(dp,0,sizeof(dp));
for(int i=1;i<=k;i++){
for(int j=1;j<=n;j++){
int tmp=dp[j-1][1][i],s=0;
for(int t=j;t>=1;t--){
s+=map[t][1];
if(s+dp[t-1][1][i-1]>tmp){tmp=s+dp[t-1][1][i-1];}
}
dp[j][1][i]=tmp;
}
}
cout<<dp[n][1][k]<<endl;
}
if(m==2){
memset(dp,0,sizeof(dp));
for(int t=1;t<=k;t++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
int tmp=dp[i-1][j][t];
tmp=max(tmp,dp[i][j-1][t]);
int s=0;
for(int i1=i;i1>=1;i1--){
s+=map[i1][1];
if(s+dp[i1-1][j][t-1]>tmp)tmp=s+dp[i1-1][j][t-1];
}
s=0;
for(int i1=j;i1>=1;i1--){
s+=map[i1][2];
if(s+dp[i][i1-1][t-1]>tmp)tmp=s+dp[i][i1-1][t-1];
}
if(i==j){
s=0;
for(int i1=j;i1>=1;i1--){
s=map[i1][1]+map[i1][2]+s;
if(s+dp[i1-1][i1-1][t-1]>tmp)tmp=s+dp[i1-1][i1-1][t-1];
}
}
dp[i][j][t]=tmp;
}
cout<<dp[n][n][k]<<endl;
}
return 0;
}