您的位置:首页 > 其它

bzoj1084: [SCOI2005]最大子矩阵

2017-05-10 18:51 423 查看

题解

  虽然是12年前的题但是并不好做。

  注意到m=1或m=2。

  当m=1时,g[i][k]表示前i个数选了k段组成的和最大是多少,且我强制选择第i个数。

  当m=2时,f[i][j][k]表示考虑了第一行的前i个,第二行的前j个数,选出k个子矩阵的最大和,不强制选择末尾的数字。

  转移可以预处理最大连续子段和。

题外话

4 2 8
4 2
3 -2
-1 -5
5 4


这组数据会把网上的大部分题解卡掉

代码

//动态规划
#include <cstdio>
#include <algorithm>
#define maxn 110
#define inf 0x3f3f3f3f
using namespace std;
int f[maxn][maxn][15], g[maxn][15], a[maxn][maxn], b[maxn][maxn], c[maxn][maxn], N, K,
M, w[maxn][maxn];
int main()
{
int i, j, k, ans=-inf, t;
scanf("%d%d%d",&N,&M,&K);
for(i=1;i<=N;i++)for(j=1;j<=M;j++)scanf("%d",&w[j][i]);
for(i=1;i<=N;i++)for(j=i;j<=N;j++)a[i][j]=max(a[i][j-1],0)+w[1][j];
for(i=1;i<=N;i++)for(j=i;j<=N;j++)b[i][j]=max(b[i][j-1],0)+w[2][j];
for(i=1;i<=N;i++)for(j=i;j<=N;j++)c[i][j]=max(0,c[i][j-1])+w[1][j]+w[2][j];
if(M==1)
{
for(i=1;i<=K;i++)g[0][i]=-inf;
for(i=1;i<=N;i++)
for(k=1;k<=K;k++)
{
g[i][k]=-inf;
for(j=0;j<i;j++)g[i][k]=max(g[i][k],g[j][k-1]+a[j+1][i]);
}
for(i=1;i<=N;i++)ans=max(ans,g[i][K]);
}
if(M==2)
{
for(i=0;i<=N;i++)for(j=1;j<=K;j++)f[i][0][j]=f[0][i][j]=-inf;
for(i=0;i<=N;i++)
for(j=0;j<=N;j++)
for(k=1;k<=K;k++)
{
if(i)f[i][j][k]=max(f[i][j][k],f[i-1][j][k]);
if(j)f[i][j][k]=max(f[i][j][k],f[i][j-1][k]);
if(i==j)
for(t=0;t<i;t++)
f[i][i][k]=max(f[i][i][k],f[t][t][k-1]+c[t+1][i]);
for(t=0;t<i;t++)f[i][j][k]=max(f[i][j][k],f[t][j][k-1]+a[t+1][i]);
for(t=0;t<j;t++)f[i][j][k]=max(f[i][j][k],f[i][t][k-1]+b[t+1][j]);
for(t=0;t<min(i,j);t++)f[i][j][k]=max(f[i][j][k],f[t][t][k-1]);
ans=max(ans,f[i][j][k]);
}
ans=f

[K];
}
printf("%d\n",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: