【BZOJ 1084】 [SCOI2005]最大子矩阵

1084: [SCOI2005]最大子矩阵

Time Limit: 10 Sec   Memory Limit: 162 MB
Submit: 1325   Solved: 670
[ Submit][ Status]

Description

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

Input

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

Output

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

Sample Input

3 2 2
1 -3
2 3
-2 3

Sample Output

9


dp。


注意到m=1/2,所以两种情况分别算。


m=1时:

f[i][j]表示前i数选出j个子矩阵,sum[i]为前缀和。


f[i][j]=max(f[i-1][j],f[k][j-1]+sum[i]-sum[k])  (0<=k<i)



m=2时:

w[i][j][k]表示左边一列的前i行,右边一列的前j行,分成k个子矩阵。


有三种转移方法:

1.从左边选择一列w[i][j][k]=max(w[i][j][k],w[p][j][k-1]+sum[i][1]-sum[p][1])


2.从右边选择一列w[i][j][k]=max(w[i][j][k],w[i][p][k-1]+sum[j][2]-sum[p][2])


3.如果i=j还可以选择宽为2的矩阵

w[i][j][k]=max(w[i][j][k],w[p][p][k-1]+sum[i][1]-sum[p][1]+sum[i][2]-sum[p][2])


这样就能把所有状态都表示出来了。


#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#define inf 0x3f3f3f3f
using namespace std;
int a[105][3],sum[105][3],f[105][105],w[105][105][15],n,m,k;
int main()
{
        scanf("%d%d%d",&n,&m,&k);
	for (int i=1;i<=n;i++)
		for (int j=1;j<=m;j++)
			scanf("%d",&a[i][j]);
	if (!k)
	{
		cout<<0<<endl;
		return 0;
	}
	if (m==1)
	{
		sum[0][1]=0;
		for (int i=1;i<=n;i++)
			sum[i][1]=sum[i-1][1]+a[i][1];
		for (int i=0;i<=n;i++)
			for (int j=1;j<=k;j++)
				f[i][j]=-inf;
		for (int i=1;i<=n;i++)
			for (int j=1;j<=min(i,k);j++)
			{
				f[i][j]=f[i-1][j];
				for (int p=0;p<i;p++)
					f[i][j]=max(f[i][j],f[p][j-1]+sum[i][1]-sum[p][1]);
			}
		cout<<f[n][k]<<endl;
	}
	else
	{
		sum[0][1]=sum[0][2]=0;
		for (int i=1;i<=n;i++)
			for (int j=1;j<=2;j++)
				sum[i][j]=sum[i-1][j]+a[i][j];
		for (int i=0;i<=n;i++)
			for (int j=0;j<=n;j++)
				for (int t=1;t<=k;t++)
					w[i][j][t]=-inf;
		for (int i=1;i<=n;i++)
			for (int j=1;j<=n;j++)
				for (int t=1;t<=min(k,i+j);t++)
				{
					w[i][j][t]=max(w[i][j-1][t],w[i-1][j][t]);
					for (int p=0;p<i;p++)
						w[i][j][t]=max(w[i][j][t],w[p][j][t-1]+sum[i][1]-sum[p][1]);
					for (int p=0;p<j;p++)
						w[i][j][t]=max(w[i][j][t],w[i][p][t-1]+sum[j][2]-sum[p][2]);
					if (i==j)
					{
						for (int p=0;p<i;p++)
							w[i][j][t]=max(w[i][j][t],w[p][p][t-1]+sum[i][1]-sum[p][1]+sum[i][2]-sum[p][2]);
					}
				}
		cout<<w[n][n][k]<<endl;
	}
	return 0;
}


感悟:

这道题的关键在于发现m的特殊之处,然后就可以暴力的来做了

你可能感兴趣的:(dp,OI,bzoj)