您的位置:首页 > 其它

[BZOJ1084][SCOI2005]最大子矩阵(dp)

2017-04-19 07:38 477 查看

题目描述

传送门

题目大意:有一个n*m的矩阵,请你选出其中至多k个子矩阵,使得这些子矩阵分值之和最大。注意:选出的子矩阵不能相互重叠。(1<=m<=2)

题解

我竟然把m分开写了

m=1随便写

m=2预处理up(i,j),down(i,j),all(i,j)表示在区间[i,j]中的第一行、第二行、两行的最长连续子序列和,f(k,i,j,0/1/2)表示选了k个,在区间[i,j]中,只选第一行/只选第二行/两行都可能有的最大值,枚举断点、上下两行选的个数,直接转移。

代码

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;

int n,m,k;

namespace type1
{
int ans;
int a[105],s[105],f[15][105];

void solve()
{
for (int i=1;i<=n;++i) scanf("%d",&a[i]),s[i]=s[i-1]+a[i];
memset(f,128,sizeof(f));
for (int i=0;i<=n;++i) f[0][i]=0;
for (int i=1;i<=k;++i)
for (int j=i;j<=n;++j)
{
f[i][j]=f[i][j-1];
for (int p=0;p<j;++p) f[i][j]=max(f[i][j],f[i-1][p]+s[j]-s[p]);
}
for (int i=1;i<=k;++i) ans=max(ans,f[i]
);
printf("%d\n",ans);
}
}
namespace type2
{
int ans,inf,a[5][105],sum[105];
int f[15][105][105][3],up[105][105],down[105][105],all[105][105];

int Max(int a,int b,int c)
{
if (a<b) a=b;
if (a<c) a=c;
return a;
}
void solve()
{
for (int i=1;i<=n;++i)
for (int j=1;j<=2;++j) scanf("%d",&a[j][i]);
for (int i=1;i<=n;++i) sum[i]=a[1][i]+a[2][i];
memset(up,128,sizeof(up)),memset(down,128,sizeof(down)),memset(all,128,sizeof(all));
for (int i=1;i<=n;++i)
{
up[i][i]=a[1][i],down[i][i]=a[2][i],all[i][i]=sum[i];
for (int j=i+1;j<=n;++j)
up[i][j]=max(up[i][j-1]+a[1][j],a[1][j]),
down[i][j]=max(down[i][j-1]+a[2][j],a[2][j]),
all[i][j]=max(all[i][j-1]+sum[j],sum[j]);
for (int j=i+1;j<=n;++j)
up[i][j]=max(up[i][j],up[i][j-1]),
down[i][j]=max(down[i][j],down[i][j-1]),
all[i][j]=max(all[i][j],all[i][j-1]);
}
memset(f,128,sizeof(f));inf=f[0][0][0][0];
for (int i=1;i<=n;++i)
for (int j=1;j<=n;++j)
f[1][i][j][0]=up[i][j],f[1][i][j][1]=down[i][j],
f[1][i][j][2]=Max(up[i][j],down[i][j],all[i][j]);
for (int i=2;i<=k;++i)
{
for (int len=1;len<=n;++len)
for (int l=1;l<=n-len+1;++l)
{
int r=l+len-1;
for (int s=0;s<=2;++s)
for (int p=l;p<r;++p)
for (int q=0;q<=i;++q)
if (f[q][l][p][s]!=inf&&f[i-q][p+1][r][s]!=inf)
f[i][l][r][s]=max(f[i][l][r][s],f[q][l][p][s]+f[i-q][p+1][r][s]);
f[i][l][r][2]=Max(f[i][l][r][0],f[i][l][r][1],f[i][l][r][2]);
for (int j=0;j<=k;++j)
if (f[j][l][r][0]!=inf&&f[i-j][l][r][1]!=inf)
f[i][l][r][2]=max(f[i][l][r][2],f[j][l][r][0]+f[i-j][l][r][1]);
}
}
for (int i=1;i<=k;++i) ans=max(ans,f[i][1]
[2]);
printf("%d\n",ans);
}
}
int main()
{
scanf("%d%d%d",&n,&m,&k);
if (m==1) type1::solve();
else type2::solve();
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: