题目链接
题解
一道区间dp好题
用f[x1][y1][x2][y2][k]状态表示:
1) 集合:划分到k−1个的子矩阵,是以(x1,y1)为左上角,(x2,y2)为右下角
2) 属性:平方和的最大值
我们按照每次分割作为状态划分依据;
模拟上述集合的划分枚举所有的区间即可
由于维数较大,五重循环过于麻烦,所以这道题我们采用记忆化搜索;
代码
#include <iostream> #include <cstring> #include <algorithm> #include <cmath> using namespace std; const int N = 15,M = 9; const int INF = 1e9; int f[M][M][M][M][N]; int s[N][N],n,m = 8; int get(int x1,int y1,int x2,int y2) { int sum = s[x2][y2] - s[x1 - 1][y2] - s[x2][y1 - 1] + s[x1 - 1][y1 - 1]; return sum * sum; } int dp(int x1, int y1, int x2, int y2, int k) { int &v = f[x1][y1][x2][y2][k]; if (v >= 0) return v; if (k == 1) return v = get(x1, y1, x2, y2); v = INF; for (int i = x1; i < x2; i ++ ) { v = min(v, get(x1, y1, i, y2) + dp(i + 1, y1, x2, y2, k - 1)); v = min(v, get(i + 1, y1, x2, y2) + dp(x1, y1, i, y2, k - 1)); } for (int i = y1; i < y2; i ++ ) { v = min(v, get(x1, y1, x2, i) + dp(x1, i + 1, x2, y2, k - 1)); v = min(v, get(x1, i + 1, x2, y2) + dp(x1, y1, x2, i, k - 1)); } return v; } int main() { cin >> n; for (int i = 1; i <= m; i ++ ) for (int j = 1; j <= m; j ++ ) { cin >> s[i][j]; s[i][j] += s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1]; } memset(f, -1, sizeof f); printf("%d", (dp(1, 1, 8, 8, n))); return 0; }