BZOJ1084

1084: [SCOI2005]最大子矩阵

Time Limit: 10 Sec   Memory Limit: 162 MB
Submit: 1152   Solved: 587
[ 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


【题解】注意看题目,m只有1和2两个值;


      那么,m==1 时 一遍DP,可以求出。j表示前j个,i 表示取了i个矩阵。f[ j ][ i ]=max( f[ i-1 ][ j ] ,f[ p ][ i-1 ]+sum[ j ]-sum[p]);

      当 m==2 时就用一个三维数组表示f[ j ][ k ][ i ],j 表示第1列的前 j 个,k 表示第二列的前 k 个, i,表示当前分了k 块。

则方程转移为:

f[j][k][i]=max(f[j-1][k][i],f[j][k-1][i]);

f[j][k][i]=max(f[j][k][i],f[p][k][i-1]+sum1[j]-sum1[p]);

f[j][k][i]=max(... , f[j][p][i-1]+sum2[k]-sum[p]);

if(j==k)f[j][k][i]=max(... , f[p][p][i-1]+sum1[j]-sum1[p]+sum2[k]-sum2[p]);

就这样可以推出答案了。



#include<cstdio>
#include<cstdlib>
#include<cstring>

#define maxn 110
#define maxk 15
#define LL long long

int w[maxn][maxk],f[maxn][maxn][maxk];
int sum[maxn],sum_[maxn];

inline LL Max(LL x,LL y){
	return x>y?x:y;
}
int main()
{
	int n,m,k;
	scanf("%d%d%d",&n,&m,&k);
	if(m==1){
		sum[0]=0;
		for(int i=1,x;i<=n;i++){
			scanf("%d",&x);
			sum[i]=sum[i-1]+x;
		}
		memset(w,0x80,sizeof(w));
		for(int i=0;i<=n;i++)w[i][0]=0;
		
		for(int i=1;i<=k;i++)
	 	 for(int j=i;j<=n;j++){
				w[j][i]=w[j-1][i];
				for(int p=0;p<j;p++)w[j][i]=(int)Max((LL)w[j][i],(LL)w[p][i-1]+sum[j]-sum[p]);
		}
		printf("%d\n",w[n][k]);
	}else{
		sum[0]=sum_[0]=0;
		for(int i=1,x1,x2;i<=n;i++){
			scanf("%d%d",&x1,&x2);
			sum[i]=sum[i-1]+x1;
			sum_[i]=sum_[i-1]+x2;
		}
		memset(f,0x80,sizeof(f));
//		printf("%d\n",f[1][1][1]);

		for(int i=0;i<=n;i++)
		for(int j=0;j<=n;j++)f[i][j][0]=0;
		 
		for(int i=1;i<=k;i++)
			for(int j=0;j<=n;j++)
			 for(int k=0;k<=n;k++){
					if(j)f[j][k][i]=f[j-1][k][i];
					if(k)f[j][k][i]=(int)Max((LL)f[j][k][i],(LL)f[j][k-1][i]);
					for(int p=0;p<j;p++)f[j][k][i]=(int)Max((LL)f[j][k][i],(LL)f[p][k][i-1]+sum[j]-sum[p]);
					for(int p=0;p<k;p++)f[j][k][i]=(int)Max((LL)f[j][k][i],(LL)f[j][p][i-1]+sum_[k]-sum_[p]);
					if(k==j)
					for(int p=0;p<k;p++)f[j][k][i]=(int)Max((LL)f[j][k][i],(LL)f[p][p][i-1]+sum[j]-sum[p]+sum_[k]-sum_[p]);	
		}
	
		printf("%d\n",f[n][n][k]);
	}
	system("pause");
	return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值