【题解】P2217 [HAOI2007] 分割矩阵 [记忆化搜索]

P2217 HAOI2007 分割矩阵 - 洛谷

题目其实有误,"均方差" 就是数学里的 "方差"

题目要我们求的其实是标准差 ,即均方差算术平方根,公式为:

其中 是每一块切出来矩阵的值和, 是矩阵总值和平均分 块的平均值。


先提前二维前缀和出矩阵值和前缀和,顺便求出平均值。

这种切割、数据范围还很小的题,基本能确定是深搜。

深搜最重要的就是结束条件 ,考虑到切成的块数是固定的,可以增加一个变量为要切成的块数

定义递归函数:

复制代码
doouble dfs(int a, int b, int c, int d, int k)
// 返回从 (a, b) 开始 (b, c) 结束的矩阵分成 k 块最小的 (x_i-ave)^2 的和

当块数为 1 时直接输出矩阵的值和。

那么这样就好做了,每次递归枚举横着切 or 竖着切,再枚举切成的两块要求切成的块数。

时间复杂度 ,炸的震天响。

考虑记忆化搜索,因为有些状态是会重复递归的。

总状态数为 ,每个状态要经过递归函数的 的时间复杂度。

总时间复杂度为 ,可以通过。

代码:

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

const int N = 12;

double mat[N][N];   // 矩阵与前缀和数组 
double ave;         // 总值和前缀和 
double dp[N][N][N][N][N];   // 记忆化搜索数组,和 dfs 对应 
// [a][b][c][d][k] 从 (a, b) 开始 (b, c) 结束的矩阵分成 k 块最小的 (x_i-ave)^2 的和 

double dfs(int a, int b, int c, int d, int k) {
// 返回从 (a, b) 开始 (b, c) 结束的矩阵分成 k 块最小的 (x_i-ave)^2 的和
	if (dp[a][b][c][d][k]) {
		return dp[a][b][c][d][k];
	}
	if (k == 1) {
		double res = mat[c][d] - mat[a - 1][d] 
			- mat[c][b - 1] + mat[a - 1][b - 1];  
			// 前缀和容斥,这里可以自己画个网格图看看 
		return (res - ave) * (res - ave); 
	}
	
	double res = 1e9;
	for (int i = a; i < c; i ++) {
		for (int j = 1; j < k; j ++) {
			double t = dfs(a, b, i, d, j) + dfs(i + 1, b, c, d, k - j);
			res = min(res, t);
		}
	}
	for (int i = b; i < d; i ++) {
		for (int j = 1; j <= k; j ++) {
			double t = dfs(a, b, c, i, j) + dfs(a, i + 1, c, d, k - j);
			res = min(res, t);
		}
	}
	
	return dp[a][b][c][d][k] = res;
}

int main () {
	ios::sync_with_stdio(false);
	cin.tie(0);
	
	int a, b, n;
	cin >> a >> b >> n;
	memset(mat, 0, sizeof(mat));
	
	for (int i = 1; i <= a; i ++) {
		for (int j = 1; j <= b; j ++) {
			cin >> mat[i][j];
		}
	}
	for (int i = 1; i <= a; i ++) {
		for (int j = 1; j <= b; j ++) {
			mat[i][j] += mat[i - 1][j] + mat[i][j - 1] - mat[i - 1][j - 1];
		}
	}
	
	ave = mat[a][b] / n;
	memset(dp, 0, sizeof(dp));
	double ans = sqrt(dfs(1, 1, a, b, n) / n);
	cout << fixed << setprecision(2) << ans << "\n";
	
	return 0;
}
相关推荐
淡海水19 分钟前
07-04-并发-ConcurrentBag-T-工作窃取WorkStealing算法
开发语言·算法·c#·bag·concurrent·workstealing
leobertlan37 分钟前
好玩系列:训练一个神经网络模型指导小孩玩游戏2-大局观教练
算法
Tisfy1 小时前
LeetCode 3876.构造奇偶一致的数组 II:三种情况分类讨论(其实还是脑筋急转弯)
算法·leetcode·题解·脑筋急转弯
乐迪信息2 小时前
智慧港口船舶AI算法实现在线状态监测
大数据·人工智能·深度学习·算法·计算机视觉
木井巳4 小时前
【BFS/DFS 解决 FloodFill 算法】太平洋大西洋水流问题
java·算法·leetcode·深度优先·广度优先·宽度优先·推荐算法
心抵鹊4 小时前
归并排序之翻转对(hard)
数据结构·算法
白山编程大哥4 小时前
Java 集合算法:从排序、查找到底层原理的实战指南
java·python·算法
_Twink1e4 小时前
openJiuwen 实训营 Day 1 · WorkSwarm 入门教程
开发语言·c++·openjiuwen
shehuiyuelaiyuehao4 小时前
算法34,位运算符操作,总结
算法
Navigator_Z5 小时前
LeetCode //C - 1224. Maximum Equal Frequency
c语言·算法·leetcode