您的位置:首页 > 其它

BZOJ1084 [SCOI2005]最大子矩阵

2016-08-21 21:48 295 查看

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

正解:DP
解题报告:
  乍一看,感觉像是才做过的那道最大子矩阵和,只不过那道题是固定了三块而这道题是k块,瞬间各种傻眼。
  结果突然发现,m<=2。。。显然可以当做特殊性质。
  f[i][j][k]表示第一列处理到第i个,第二列处理到第j个并且选取了k个子矩阵的最优值。转移的话要不从左边选择一块,要不从右边选择一块,又或者两列都占的矩形,但是只有i、j相等才可能两列都占,否则无法刚好到达i。
  代码如下:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int MAXN = 150;
int n,m,k;
int dp[MAXN][11],f[MAXN][MAXN][11];
int a[2][MAXN];
int sum[2][MAXN];

inline int getint(){
int w=0,q=1;char c=getchar();
while(c!='-' && (c<'0' || c>'9')) c=getchar();
if(c=='-') q=-1,c=getchar();
while(c>='0' && c<='9') w=w*10+c-'0',c=getchar();
return w*q;
}

int main()
{
n=getint(); m=getint(); k=getint();
if(m==1) {//特判只有一列的情况
for(int i=1;i<=n;i++) a[0][i]=getint(),sum[0][i]=sum[0][i-1]+a[0][i];

for(int i=1;i<=n;i++)
for(int l=1;l<=k;l++) {
dp[i][l]=dp[i-1][l];
for(int j=0;j<i;j++)
dp[i][l]=max(dp[j][l-1]+sum[0][i]-sum[0][j],dp[i][l]);
}
printf("%d",dp
[k]);

} else{
for(int i=1;i<=n;i++) a[0][i]=getint(),sum[0][i]=sum[0][i-1]+a[0][i],a[1][i]=getint(),sum[1][i]=sum[1][i-1]+a[1][i];

for(int l=1;l<=k;l++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++) {
f[i][j][l]=max(f[i-1][j][l],f[i][j-1][l]);
for(int from=0;from<i;from++) f[i][j][l]=max(f[i][j][l],f[from][j][l-1]+sum[0][i]-sum[0][from]);//枚举从左边转移
for(int from=0;from<j;from++) f[i][j][l]=max(f[i][j][l],f[i][from][l-1]+sum[1][j]-sum[1][from]);//枚举从右边转移
if(i==j)
for(int from=0;from<i;from++)//枚举从两边转移
f[i][j][l]=max(f[i][j][l],f[from][from][l-1]+sum[0][i]-sum[0][from]+sum[1][j]-sum[1][from]);
}
printf("%d",f

[k]);
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: