首页 > 代码库 > BZOJ 1084 SCOI2005 最大子矩阵 动态规划

BZOJ 1084 SCOI2005 最大子矩阵 动态规划

题目大意:给出一个矩阵,求在这个矩阵中取出k个不重叠的矩阵的最大和。


思路:怎么做?

这个问题困扰我好几天的时间,终于再一次读题:

。。。

。。

。。。

2??!!

这尼玛逗我??直接说最多两列不好么?还用矩阵吓唬我?

好吧下次我一定认真看题。。

我的做法比较渣,算出来的时间复杂度是O(m^3*k),但是只有最多3000w,还是可以过的。

状态:f[i][j][k]表示第一列到了第i个格子,第二列到了第j个格子,已经选取了k个矩阵的最大得数。

转移:先把现有的状态向后转移,转移成f[i‘][j‘][k],然后取矩阵,向后转移,转移成f[i‘][j‘][k + 1]。这里要分三种情况讨论,转移第一列,转移第二列,和两列一起转移。


CODE:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 110
using namespace std;

int m,n,c;
int src[MAX][3],sum[3][MAX];
int f[MAX][MAX][15];

int main()
{
	cin >> m >> n >> c;
	for(int i = 1; i <= m; ++i)
		for(int j = 1; j <= n; ++j) {
			scanf("%d",&src[i][j]);
			sum[j][i] = sum[j][i - 1] + src[i][j];
		}
	int ans = 0;
	if(n == 1) {
		for(int i = 0; i <= m; ++i)
			for(int k = 0; k <= c; ++k)
				for(int _i = i + 1; _i <= m; ++_i) {
					f[_i][k][0] = max(f[_i][k][0],f[i][k][0]);
					f[_i][k + 1][0] = max(f[_i][k + 1][0],f[i][k][0] + sum[1][_i] - sum[1][i]);
				}
		for(int i = 0; i <= m; ++i)
			for(int k = 0; k <= c; ++k)
				ans = max(ans,f[i][k][0]);
	}
	else {
		for(int i = 0; i <= m; ++i)
			for(int j = 0; j <= m; ++j)
				for(int k = 0; k <= c; ++k) {
					for(int _i = i + 1; _i <= m; ++_i) {
						f[_i][j][k] = max(f[_i][j][k],f[i][j][k]);
						f[_i][j][k + 1] = max(f[_i][j][k + 1],f[i][j][k] + sum[1][_i] - sum[1][i]);
					}
					for(int _j = j + 1; _j <= m; ++_j) {
						f[i][_j][k] = max(f[i][_j][k],f[i][j][k]);
						f[i][_j][k + 1] = max(f[i][_j][k + 1],f[i][j][k] + sum[2][_j] - sum[2][j]);
					}
					for(int _k = max(i,j) + 1; _k <= m; ++_k) {
						f[_k][_k][k] = max(f[_k][_k][k],f[i][j][k]);
						f[_k][_k][k + 1] = max(f[_k][_k][k + 1],f[i][j][k] + sum[1][_k] - sum[1][max(i,j)] + sum[2][_k] - sum[2][max(i,j)]);
					}
				}
		for(int i = 0; i <= m; ++i)
			for(int j = 0; j <= m; ++j)
				for(int k = 0; k <= c; ++k)
					ans = max(ans,f[i][j][k]);
	}
	cout << ans << endl;
	return 0;
}


BZOJ 1084 SCOI2005 最大子矩阵 动态规划