您的位置:首页 > 其它

【BZOJ 1084】 [SCOI2005]最大子矩阵

2015-02-21 00:09 274 查看

1084: [SCOI2005]最大子矩阵

Time Limit: 10 Sec Memory Limit: 162 MB

Submit: 1325 Solved: 670

[Submit][Status]

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。

注意到m=1/2,所以两种情况分别算。

m=1时:

f[i][j]表示前i数选出j个子矩阵,sum[i]为前缀和。

f[i][j]=max(f[i-1][j],f[k][j-1]+sum[i]-sum[k]) (0<=k<i)

m=2时:

w[i][j][k]表示左边一列的前i行,右边一列的前j行,分成k个子矩阵。

有三种转移方法:

1.从左边选择一列w[i][j][k]=max(w[i][j][k],w[p][j][k-1]+sum[i][1]-sum[p][1])

2.从右边选择一列w[i][j][k]=max(w[i][j][k],w[i][p][k-1]+sum[j][2]-sum[p][2])

3.如果i=j还可以选择宽为2的矩阵

w[i][j][k]=max(w[i][j][k],w[p][p][k-1]+sum[i][1]-sum[p][1]+sum[i][2]-sum[p][2])

这样就能把所有状态都表示出来了。

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#define inf 0x3f3f3f3f
using namespace std;
int a[105][3],sum[105][3],f[105][105],w[105][105][15],n,m,k;
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",&a[i][j]);
if (!k)
{
cout<<0<<endl;
return 0;
}
if (m==1)
{
sum[0][1]=0;
for (int i=1;i<=n;i++)
sum[i][1]=sum[i-1][1]+a[i][1];
for (int i=0;i<=n;i++)
for (int j=1;j<=k;j++)
f[i][j]=-inf;
for (int i=1;i<=n;i++)
for (int j=1;j<=min(i,k);j++)
{
f[i][j]=f[i-1][j];
for (int p=0;p<i;p++)
f[i][j]=max(f[i][j],f[p][j-1]+sum[i][1]-sum[p][1]);
}
cout<<f
[k]<<endl;
}
else
{
sum[0][1]=sum[0][2]=0;
for (int i=1;i<=n;i++)
for (int j=1;j<=2;j++)
sum[i][j]=sum[i-1][j]+a[i][j];
for (int i=0;i<=n;i++)
for (int j=0;j<=n;j++)
for (int t=1;t<=k;t++)
w[i][j][t]=-inf;
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
for (int t=1;t<=min(k,i+j);t++)
{
w[i][j][t]=max(w[i][j-1][t],w[i-1][j][t]);
for (int p=0;p<i;p++)
w[i][j][t]=max(w[i][j][t],w[p][j][t-1]+sum[i][1]-sum[p][1]);
for (int p=0;p<j;p++)
w[i][j][t]=max(w[i][j][t],w[i][p][t-1]+sum[j][2]-sum[p][2]);
if (i==j)
{
for (int p=0;p<i;p++)
w[i][j][t]=max(w[i][j][t],w[p][p][t-1]+sum[i][1]-sum[p][1]+sum[i][2]-sum[p][2]);
}
}
cout<<w

[k]<<endl;
}
return 0;
}



感悟:

这道题的关键在于发现m的特殊之处,然后就可以暴力的来做了
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: