您的位置:首页 > 其它

【BZOJ 1084】【SCOI 2005】最大子矩阵【DP & 分类讨论】

2017-03-09 23:41 453 查看

Description

  这里有一个n*m的矩阵,请你选出其中k个子矩阵,使得这个k个子矩阵分值之和最大。注意:选出的k个子矩阵不能相互重叠。

Input

  第一行为n,m,k(1≤n≤100,1≤m≤2,1≤k≤10),接下来n行描述矩阵每行中的每个元素的分值(每个元素的分值的绝对值不超过32767)。

Output

  只有一行为k个子矩阵分值之和最大为多少。

题解

又题意可知,m非常小(<=2 !!!),所以分类讨论的DP

① m=1

 设f[i][k]表示前i个数取了k个矩阵的最优解

 1、选,f[i][k] = max{f[pos][k-1]+sum[i][1]-sum[pos][1]}

 2、不选,f[i][k] = max{f[i-1][k],f[i][k]}

② m=1

 设w[i][j][k]:第一行取i个,第二行取j个,以取了k个矩阵的最优解

 1、什么都不干

  w[i][j][k] = max{w[i-1][j][k],w[i][j-1][k]}

 2、只从第一段中取

  w[i][j][k] = max{w[pos][j][k-1]+sum[i][1]-sum[pos][1]}

 3、只从第二段中取

  w[i][j][k] = max{w[i][pos][k-1]+sum[j][2]-sum[pos][2]}

 4、当i==j时,可以两列一起取

  w[i][j][k] = max{w[pos][pos][k-1]+sum[i][1]+sum[j][1]-sum[pos][1]-sum[pos][2]}

取所有的max就可以啦

代码

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

#define rep(i,x,y) for(int i = x;i <= y;i++)
#define N 105
#define inf 32768
int a,f
[15],w

[15],sum
[3];
int n,m,K;

int main()
{
scanf("%d%d%d",&n,&m,&K);
memset(sum,0,sizeof(sum));
rep(i,1,n)
rep(j,1,m)
{
scanf("%d",&a);
sum[i][j] = sum[i-1][j] + a;
}
if(m == 1)
{
rep(i,0,n) rep(k,1,K) f[i][k] = -inf;
rep(i,1,n)
rep(k,1,K)
{
f[i][k] = f[i-1][k];
for(int pos = 0;pos < i;pos++)
f[i][k] = max(f[i][k],f[pos][k-1]+sum[i][1]-sum[pos][1]);
}
printf("%d\n",f
[K]);
}
else
{
rep(i,0,n) rep(j,0,n) rep(k,1,K) w[i][j][k] = -inf;
rep(i,1,n) rep(j,1,n) rep(k,1,K)
{
w[i][j][k] = max(w[i-1][j][k],w[i][j-1][k]);
rep(pos,0,i-1)
w[i][j][k] = max(w[i][j][k],w[pos][j][k-1]+sum[i][1]-sum[pos][1]);
rep(pos,0,j-1)
w[i][j][k] = max(w[i][j][k],w[i][pos][k-1]+sum[j][2]-sum[pos][2]);
if(i == j)
rep(pos,0,i-1)
w[i][j][k] = max(w[i][j][k],w[pos][pos][k-1]+sum[i][1]-sum[pos][1]+sum[j][2]-sum[pos][2]);
}
printf("%d\n",w

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