BZOJ1084&&洛谷P2331 [SCOI2005]最大子矩陣
阿新 • • 發佈:2018-12-17
DP+思維
思路
這道題的切入點是,發現只有兩種取值,那麼我們就可以嘗試對分類討論
m=1
發現在時就是在一個一維序列上做k個最大子段和,我們定義表示處理到第位,共個矩陣的最大和,咋轉移? 假設這一位不選,那就是 否則列舉上一個矩形結束位置,那麼 s是字首和 最後輸出就好了
m=2
在二維下,我們類比一維,但是因為一個矩形可以佔據一列 ,也可以佔據兩列,所以我們定義表示第一列到第行,第二列到第行,共k個矩形的最大和,如何轉移?我們列舉, 都不選, 考慮在第一列上轉移,列舉,可以得到 考慮在第二列上轉移,列舉,可以得到 考慮兩列一起轉移,這樣的情況存在,當且僅當時,這樣才能構造出一個新矩形,然後我們列舉一個p,可以得到 是第一列字首和,是第二列字首和 最後輸出
程式碼
//By AcerMo
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int M=105;
int n,m,e,a[M][3];
int s1[M],s2[M],f[M][M],g[M][M][M];
signed main()
{
scanf("%d%d%d",&n,&m,&e);
for (int i=1;i<=n;i++)
for (int k=1;k<=m;k++)
scanf("%d",&a[i][k]);
if (m==1)
{
for (int i=1;i<=n;i++)
s1[i]=s1[i-1]+a[i][1];
for (int i=1;i<=e;i++)
for (int k=1;k<=n;k++)
{
f[k][i]=f[k-1][i];
for (int j=0;j<k;j++)
f[k][i]=max(f[k][i],f[j][i-1]+s1[k]-s1[j]);
}
return printf("%d",f[n][e]),0;
}
for (int i=1;i<=n;i++)
s1[i]=s1[i-1]+a[i][1],
s2[i]=s2[i-1]+a[i][2];
for (int i=1;i<=e;i++)
for (int k=1;k<=n;k++)
for (int j=1;j<=n;j++)
{
g[k][j][i]=max(g[k-1][j][i],g[k][j-1][i]);
for (int p=0;p<k;p++)
g[k][j][i]=max(g[k][j][i],g[p][j][i-1]+s1[k]-s1[p]);
for (int p=0;p<j;p++)
g[k][j][i]=max(g[k][j][i],g[k][p][i-1]+s2[j]-s2[p]);
if (k==j)
for (int p=0;p<k;p++)
g[k][j][i]=max(g[k][j][i],g[p][p][i-1]+s1[k]+s2[j]-s1[p]-s2[p]);
}
printf("%d",g[n][n][e]);
return 0;
}