思路:分析公式,我们可以发现平均值那一项和我们怎么分的具体方案无关,影响答案的是每个矩阵的矩阵和的平方,由于数据很小,我们可以预处理出每个矩阵的和的平方,执行状态转移。
设dp[l1][r1][l2][r2][k]是矩阵l1,r1,l2,r2切割k次的最小值,我们可以枚举是横着切还是竖着切执行状态转移。
代码:
#include <cstdio> #include <algorithm> #include <cstring> #include <cmath> #define INF 0x3f3f3f3f using namespace std; int dp[10][10][10][10][16], sum[10][10][10][10]; bool v[10][10][10][10][16]; int a[10][10]; void init() { for (int l1 = 1; l1 <= 8; l1++) for (int r1 = 1; r1 <= 8; r1++) for (int l2 = l1; l2 <= 8; l2++) for (int r2 = r1; r2 <= 8; r2++) { int ans = 0; for (int i = l1; i <= l2; i++) for (int j = r1; j <= r2; j++) { ans += a[i][j]; } sum[l1][r1][l2][r2] = ans * ans; } } int solve(int l1, int r1, int l2, int r2, int k) { if (v[l1][r1][l2][r2][k]) return dp[l1][r1][l2][r2][k]; if (k == 1) { return dp[l1][r1][l2][r2][k] = sum[l1][r1][l2][r2]; } int ans = INF; for (int i = l1; i < l2; i++) { ans = min(ans, min(solve(l1, r1, i, r2, k - 1) + sum[i + 1][r1][l2][r2], solve(i + 1, r1, l2, r2, k - 1) + sum[l1][r1][i][r2])); } for (int i = r1; i < r2; i++) { ans = min(ans, min(solve(l1, r1, l2, i, k - 1) + sum[l1][i + 1][l2][r2], solve(l1, i + 1, l2, r2, k - 1) + sum[l1][r1][l2][i])); } v[l1][r1][l2][r2][k] = 1; return dp[l1][r1][l2][r2][k] = ans; } int main() { int n, tot = 0; scanf("%d", &n); for (int i = 1; i <= 8; i ++) { for (int j = 1; j <= 8 ; j++) { scanf("%d", &a[i][j]); tot += a[i][j]; } } init(); solve(1, 1, 8, 8, n); double ans = sqrt(dp[1][1][8][8][n] * 1.0 / n - (tot * 1.0 / n) * (tot * 1.0 / n)); printf("%.3f ", ans); }