bzoj1084: [SCOI2005]最大子矩阵(DP)

原题链接

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

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

输出格式:只有一行为k个子矩阵分值之和最大为多少。

输入样例
3 2 2
1 -3
2 3
-2 3

输出格式
9

解析:注意1≤m≤2!
   当m=1时,很容易想到可以用DP解决。
   设dp[i][j]表示前i个数,取了j个矩阵的最大值。
   如果不选,dp[i][j]=max(dp[i][j],dp[i-1][j)。
   如果选,dp[i][j]=max(dp[i][j],dp[l][j-1]+sum[i]-sum[l])。
   当m=2时,也考虑用DP进行解决。
   设f[i][j][k]表示第一列选到了第i个,第二列选到了第j个,一共选了k个矩阵的最大值。
   那么有以下几种情况。
   若不选,f[i][j][k]=max(f[i-1][j][k],f[i][j-1][k])。
   若只选第一列,f[i][j][k]=max(f[i][j][k],f[l][j][k-1]+sum[i][0]-sum[l][0])。
   若只选第二列,f[i][j][k]=max(f[i][j][k],f[i][l][k-1]+sum[j][1]-sum[l][1])。
   当i=j时,可以两行都选。
   同时可以两行当成一个矩阵选,也可以当成两个矩阵选。
   若当成一个矩阵,f[i][j][k]=max(f[i][j][k],f[l][l][k-1]+sum[i][0]-sum[l][0]+sum[j][1]-sum[l][1])。
   若当成两个矩阵,f[i][j][k]=max(f[i][j][k],f[l][l][k-2]+sum[i][0]-sum[l][0]+sum[j][1]-sum[l][1])。

代码如下:

#include<cstdio>
#include<algorithm>
using namespace std;

const int maxn = 105;
int n, m, k, a[maxn][maxn], dp[maxn][maxn], sum[maxn][2];
int f[maxn][maxn][maxn];

int read(void) {
	char c; while (c = getchar(), (c < '0' || c > '9') && c != '-'); int x = 0, y = 1;
	if (c == '-') y = -1; else x = c - '0';
	while (c = getchar(), c >= '0' && c <= '9') x = x * 10 + c - '0'; return x * y; 
}

void subtask1(void) {
	for (int i = 1; i <= n; ++ i) sum[i][0] = sum[i - 1][0] + a[i][1];
	for (int i = 1; i <= n; ++ i)
	  for (int j = 1; j <= k; ++ j) 
	    for (int h = i - 1; h >= 0 ; -- h) {
	      dp[i][j] = max(dp[i][j], dp[i - 1][j]);
	      dp[i][j] = max(dp[i][j], dp[h][j - 1] + sum[i][0] - sum[h][0]);
		}
	printf("%d", dp[n][k]);
}

void subtask2(void) {
	for (int i = 1; i <= n; ++ i) {
	  sum[i][0] = sum[i - 1][0] + a[i][1];
	  sum[i][1] = sum[i - 1][1] + a[i][2];
	}
	for (int i = 1; i <= n; ++ i) 
	  for (int j = 1; j <= n; ++ j)
	    for (int h = 1; h <= k; ++ h) {
	      f[i][j][h] = max(f[i - 1][j][h], f[i][j - 1][h]);
	      for (int l = i - 1; l >= 0; -- l) f[i][j][h] = max(f[i][j][h], f[l][j][h - 1] + sum[i][0] - sum[l][0]);
	      for (int l = j - 1; l >= 0; -- l) f[i][j][h] = max(f[i][j][h], f[i][l][h - 1] + sum[j][1] - sum[l][1]);
	      if (i == j) {
	      	for (int l = i - 1; l >= 0; -- l) {
	      		f[i][j][h] = max(f[i][j][h], f[l][l][h - 1] + sum[i][0] - sum[l][0] + sum[j][1] - sum[l][1]);
	      	    if (h > 1) f[i][j][h] = max(f[i][j][h], f[l][l][h - 2] + sum[i][0] - sum[l][0] + sum[j][1] - sum[l][1]);
			  }
		  }
		}
	printf("%d", f[n][n][k]);
}

int main() {
	n = read(); m = read(); k = read();
	  for (int i = 1; i <= n; ++ i)
	    for (int j = 1; j <= m; ++ j) a[i][j] = read();
	  if (m == 1) subtask1();
	  else subtask2();
	return 0;
} 
posted @ 2019-01-01 18:20  Gax_c  阅读(168)  评论(0编辑  收藏  举报