P2331 [SCOI2005]最大子矩阵

P2331 [SCOI2005]最大子矩阵

0x01 题意

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

其中\(1\le n\le 100,1\le m\le 2,1\le k\le 10.\)

0x02 解

\(m\)只有\(1\)\(2\)两种取值,所以直接讨论就好

\(m=1\)时:

是前\(k\)个最大连续字段和

定义\(f[i][j]\)为前\(i\)个数中取出\(j\)个矩形的最大和

则有:

\[\begin{aligned} &选:f[i][j]=max(f[k-1][j-1]+s[i]-s[k-1])\\ &不选:f[i][j]=max(f[i][j],f[i-1][j]) \end{aligned} \]

\(m=2\)时:

定义\(f[i][j][p]\)为第一列选到第\(i\)个数,第二列选到第\(j\)个数时,总共\(k\)个子矩阵的最大和

则有:

\[\begin{aligned} &不选:f[i][j][p]=max(f[i-1][j][p],f[i][j-1][p])\\ &选第一列:f[i][j][p]=max(f[k-1][j][p-1]+s1[i]-s1[k-1])\\ &选第二列:f[i][j][p]=max(f[i][k-1][p-1]+s2[j]-s2[k-1])\\ &选两列:if(i==j) f[i][j][p]=max(f[k-1][k-1][p-1]+s1[i]+s2[i]-s1[k-1]-s2[k-1]) \end{aligned} \]

注意\(k\)的边界

0x03 码

#include<bits/stdc++.h>
using namespace std;
const int N =110;

int n,m,k,s1[N],s2[N],f[N][N][N];
int main(){
	
	memset(f,0,sizeof f);
	memset(s1,0,sizeof s1);
	memset(s2,0,sizeof s2);
	scanf("%d%d%d",&n,&m,&k);
	
	int o;
	for(int i=1;i<=n;i++){
		if(m==1) scanf("%d",&o),s1[i]=s1[i-1]+o;
		else{
			scanf("%d",&o);
			s1[i]=s1[i-1]+o;
			scanf("%d",&o);
			s2[i]=s2[i-1]+o;
		}
	}
	
	if(m==1){
		
		for(int p=1;p<=k;p++){
			for(int i=1;i<=n;i++){
				f[i][p][0]=max(f[i][p][0],f[i-1][p][0]);
				for(int j=1;j<=i;j++) f[i][p][0]=max(f[i][p][0],f[j-1][p-1][0]+s1[i]-s1[j-1]);
			}
		}
		printf("%d\n",f[n][k][0]);
		
	}else{
		
		for(int p=1;p<=k;p++){
			for(int i=1;i<=n;i++){
				for(int j=1;j<=n;j++){
					f[i][j][p]=max(f[i-1][j][p],f[i][j-1][p]);
					for(int r=1;r<=i;r++) f[i][j][p]=max(f[i][j][p],f[r-1][j][p-1]+s1[i]-s1[r-1]);
					for(int r=1;r<=j;r++) f[i][j][p]=max(f[i][j][p],f[i][r-1][p-1]+s2[j]-s2[r-1]);
					if(i==j) for(int r=1;r<=i;r++) f[i][j][p]=max(f[i][j][p],f[r-1][r-1][p-1]+s1[i]+s2[j]-s1[r-1]-s2[r-1]);
				}
			}
		}
		
		printf("%d\n",f[n][n][k]);
		
	}
	
	
	
	return 0;
}
posted @ 2021-03-08 08:36  wsy_jim  阅读(62)  评论(0编辑  收藏  举报