#include using namespace std; const int N = 10; // 8*8个格子,我们从下标1开始放入,需要用到下标8,开10个。 const int INF = 0x3f3f3f3f; int n; int m = 8; int s[N][N]; // 二维前缀和 double f[N][N][N][N][N]; // DP结果数组 // 二维前缀和应用 int get_sum(int x1, int y1, int x2, int y2) { return s[x2][y2] - s[x2][y1 - 1] - s[x1 - 1][y2] + s[x1 - 1][y1 - 1]; } // 均方差公式[模拟了题目给的公式] 注意这里没有开根号,最后开一次根号就行 double get(int x1, int y1, int x2, int y2) { // 利用二维前缀和的结果,计算出平均值,注意要使用double的类型转换,防止丢失精度 double X = (double)s[m][m] / n; // 平均数 double sum = get_sum(x1, y1, x2, y2) - X; return sum * sum; } /** * 功能:记忆化搜索 * @param x1 左上角x坐标 * @param y1 左上角y坐标 * @param x2 右下角x坐标 * @param y2 右下角y坐标 * @param k 剩余的刀数 * @return 根据公式计算出的最小值 */ double dfs(int x1, int y1, int x2, int y2, int k) { double &v = f[x1][y1][x2][y2][k]; if (v >= 0) return v; // 计算过了,就直接返回,不再重复计算,v是一个double,不能用~判断是不是-1 if (k == 0) return v = get(x1, y1, x2, y2); // 如果k=0,表示刀都用完了,最终这一块可以计算出来了 // v:-1 表示没有计算过 v:INF 马上要进行计算,先设置最大 v = INF; // 每次枚举的是i和i + 1之间分界线 // 选择横着切,从x1行开始(这个是固定的),到i行(需要枚举的)结束 for (int i = x1; i < x2; i++) { // 放弃上半部分,选择下半部分 v = min(v, get(x1, y1, i, y2) + dfs(i + 1, y1, x2, y2, k - 1)); // 放弃下半部分,选择上半部分 v = min(v, get(i + 1, y1, x2, y2) + dfs(x1, y1, i, y2, k - 1)); } // 选择纵着切 for (int i = y1; i < y2; i++) { // 放弃左半部分,选择右半部分 v = min(v, get(x1, y1, x2, i) + dfs(x1, i + 1, x2, y2, k - 1)); // 放弃右半部分,选择左半部分 v = min(v, get(x1, i + 1, x2, y2) + dfs(x1, y1, x2, i, k - 1)); } // 返回打擂台的最小值 return v; } int main() { scanf("%d", &n); // 切成n块 for (int i = 1; i <= m; i++) for (int j = 1; j <= m; j++) { // 原数组不用保存,直接用一个二维前缀和数组s即可 scanf("%d", &s[i][j]); // 二维前缀和 s[i][j] += s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1]; } // 将DP数组初始化为负无穷,计算过的>=0 (因为均方差可能为0),未计算过的为-1,方便获取哪个位置是否计算过 // 问题:为什么不用memset(f, -1, sizeof f)? // 答:一般double类型的数组初始化,喜欢用多重循环,不喜欢用memset,可能会有坑,当然,本题用memset也正确 for (int k = 0; k < 15; k++) for (int x1 = 1; x1 <= m; x1++) for (int y1 = 1; y1 <= m; y1++) for (int x2 = 1; x2 <= m; x2++) for (int y2 = 1; y2 <= m; y2++) f[x1][y1][x2][y2][k] = -1; // 记忆化搜索:因为最后需要切出n块矩形棋盘,其实就是需要切n-1刀,开始dfs模拟 printf("%.3lf\n", sqrt(dfs(1, 1, 8, 8, n - 1) / n)); return 0; }