1. 程式人生 > >BZOJ1084&&洛谷P2331 [SCOI2005]最大子矩陣

BZOJ1084&&洛谷P2331 [SCOI2005]最大子矩陣

DP+思維

思路

這道題的切入點是mm,發現mm只有兩種取值,那麼我們就可以嘗試對mm分類討論

m=1

發現在m=1m=1時就是在一個一維序列上做k個最大子段和,我們定義f[i][j]f[i][j]表示處理到第ii位,共jj個矩陣的最大和,咋轉移? 1.1. 假設這一位不選,那就是f[i][j]=f[i1][j]f[i][j]=f[i-1][j] 2.2.否則列舉上一個矩形結束位置kk,那麼 f[i][j]=max(f[i][j],f[k][j1]+s[k]s[j]f[i][j]=max(f[i][j],f[k][j-1]+s[k]-s[j]

s是字首和 最後輸出f[n][e]f[n][e]就好了

m=2

在二維下,我們類比一維,但是因為一個矩形可以佔據一列 ,也可以佔據兩列,所以我們定義g[i][j][k]g[i][j][k]表示第一列到第ii行,第二列到第jj行,共k個矩形的最大和,如何轉移?我們列舉iijj 1.1.iji,j都不選,g[i][j][k]=max(g[i1][j][k],g[i][j1][k])g[i][j][k]=max(g[i-1][j][k],g[i][j-1][k])

2.2.考慮在第一列上轉移,列舉pp,可以得到 g[i][j][k]=max(g[i][j][k],g[p][j][k1]+s1[i]s1[p])g[i][j][k]=max(g[i][j][k],g[p][j][k-1]+s1[i]-s1[p]) 3.3.考慮在第二列上轉移,列舉pp,可以得到 g[i][j][k]=max(g[i][j][k],g[i][p][k1]+s2[j]s2[p]
)g[i][j][k]=max(g[i][j][k],g[i][p][k-1]+s2[j]-s2[p])
4.4.考慮兩列一起轉移,這樣的情況存在,當且僅當i=ji=j時,這樣才能構造出一個新矩形,然後我們列舉一個p,可以得到 g[i][j][k]=max(g[i][j][k],g[p][p][k1]+s1[i]s1[p]+s2[j]s2[p])g[i][j][k]=max(g[i][j][k],g[p][p][k-1]+s1[i]-s1[p]+s2[j]-s2[p]) s1s1是第一列字首和,s2s2是第二列字首和 最後輸出g[n][n][e]g[n][n][e]

程式碼

//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;
}