bzoj1084[SCOI2005]最大子矩阵

fijk表示第一列选了i个第二列选了j个已经搞定了k个子矩阵的情况

然后考虑转移,可以不选,从上面转移作为初值,可以选,于是枚举之前的进行转移就行

实际上我们看到了m<=2并想到了分类转移的思想的时候已经变得很简单了

听说丽洁姐姐的博客里面有详细,但是并不能打开【大概是RP不好

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#define LL long long
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define down(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
inline LL read()
{
	LL d=0,f=1;char s=getchar();
	while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
	while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();}
	return d*f;
}
#define N 105
#define M 15
#define NM 5
int a[N][M],s[N][M];
int f[N][N][M];
int n,m,nm,ans=0;

void init()
{
	memset(s,0,sizeof(s));
	n=read(),m=read(),nm=read();
	fo(i,1,n)
	{
		fo(j,1,m)
		{
			int x=read();
			a[i][j]=x;
			s[i][j]=s[i-1][j]+a[i][j];
		}
	}
}

void ini()
{
	memset(s,0,sizeof(s));
	scanf("%d%d%d",&n,&m,&nm);
	fo(i,1,n)
	{
		fo(j,1,m)
		{
			int x;
			scanf("%d",&x);
			a[i][j]=x;
			s[i][j]=s[i-1][j]+a[i][j];
		}
	}
}

void DP()
{
	memset(f,0,sizeof(f));
	fo(p,1,nm)
	fo(i,1,n)
	fo(j,1,n)
	{
		f[i][j][p]=max(f[i-1][j][p],f[i][j-1][p]);
		fo(q,0,max(i,j)-1)
		{
			if(i==j)
			{
				f[i][j][p]=max(f[i][j][p],f[q][q][p-1]+s[i][1]-s[q][1]+s[j][2]-s[q][2]);
			}
			if(q<j)f[i][j][p]=max(f[i][j][p],f[i][q][p-1]+s[j][2]-s[q][2]);
			if(q<i)f[i][j][p]=max(f[i][j][p],f[q][j][p-1]+s[i][1]-s[q][1]);
		}
	}
}

void OUT()
{
	cout<<f[n][n][nm]<<endl;
}

int main()
{
	ini();
	DP();
	OUT();
	return 0;
}


你可能感兴趣的:(dp)