题解 :棋盘分割

该博客探讨了一个数学问题,即如何将一个棋盘划分为n个部分,使得各部分的分值平方和最小。通过化简均方差公式,问题转化为寻找最小平方和。博主利用动态规划方法,结合二维前缀和,建立状态转移方程,求解最优解。最后给出了C++代码实现。
摘要由CSDN通过智能技术生成

题面


分析:

      看到题目,我们首先要 将均方差 的公式化简:
       σ = ∑ i = 1 n ( x i − x ) 2 n ( x = ∑ i = 1 n x i n ,即平均数 ) \sigma = \sqrt{\frac{\sum_{i = 1}^{n}(x_i - x)^2}{n}} (x = \frac{\sum_{i = 1}^n x_i}{n},即平均数) σ=ni=1n(xix)2 (x=ni=1nxi,即平均数)


       σ 2 = ∑ i = 1 n ( x i − x ) 2 n \sigma^2 = \frac{\sum_{i = 1}^{n}(x_i - x)^2}{n} σ2=ni=1n(xix)2


       n ∗ σ 2 = ∑ i = 1 n ( x i − x ) 2 n * \sigma^2 = \sum_{i = 1}^{n}(x_i - x)^2 nσ2=i=1n(xix)2


       n ∗ σ 2 = ∑ i = 1 n ( x i 2 − 2 ∗ x i ∗ x + x 2 ) n * \sigma^2 = \sum_{i = 1}^{n}(x_i^2 - 2 * x_i * x + x^2) nσ2=i=1n(xi22xix+x2)


       n ∗ σ 2 = ∑ i = 1 n x i 2 − 2 ∗ x ∗ ∑ i = 1 n x i + n ∗ x 2 n * \sigma^2 = \sum_{i = 1}^{n}x_i^2 - 2 *x * \sum_{i = 1}^{n}x_i + n * x^2 nσ2=i=1nxi22xi=1nxi+nx2


      将 x = ∑ i = 1 n x i n x = \frac{\sum_{i = 1}^n x_i}{n} x=ni=1nxi 变形得到 n ∗ x = ∑ i = 1 n x i n *x = \sum_{i = 1}^{n} x_i nx=i=1nxi并带入上式:


       n ∗ σ 2 = ∑ i = 1 n x i 2 − 2 ∗ n ∗ x 2 + n ∗ x 2 n * \sigma^2 = \sum_{i = 1}^{n}x_i^2 - 2 * n * x^2 +n * x^2 nσ2=i=1nxi22nx2+nx2


       n ∗ σ 2 = ∑ i = 1 n x i 2 − n ∗ x 2 n * \sigma^2 = \sum_{i = 1}^{n}x_i^2 - n * x^2 nσ2=i=1nxi2nx2


      因为无论怎样划分 ∑ i = 1 n x i \sum_{i = 1}^{n}x_i i=1nxi 都是固定的,即整块棋盘的总分值,又因为 n n n 给定且大于 0 0 0,所以 x x x 也是固定的。那么 n ∗ x 2 n * x^2 nx2 也是定值。    现在要使得 σ \sigma σ 最小,则 ∑ i = 1 n x i 2 − n ∗ x 2 \sum_{i = 1}^{n}x_i^2 - n * x^2 i=1nxi2nx2 就要最小,则 ∑ i = 1 n x i 2 \sum_{i = 1}^{n}x_i ^2 i=1nxi2 就要最小。


      现在问题转化为了 将原棋盘按规则分成 n n n 块且每一块分值的平方最小。 我们考虑到 大矩阵是由小矩阵拼接而成。例如我要将一个大矩阵分成 k k k 块,那么其实相当于把它分成两小块,其中一块是已经确定的,另一小块要再被分成 k − 1 k - 1 k1 块。根据 DP最优子结构的性质我们知道: k k k 一定是这个动态规划的阶段。而且本题与 区间DP 非常相似,可看作 二维区间DP 来做,区间长度对应的就是 k k k


      因为对于一个大矩阵而言,将他分为两个矩阵的方式有两种 (竖着切或横着切),而在切完后要选择一个小矩阵作为剩余矩阵接着切,有两种选择小矩阵的方法。于是我们要分情况进行比较,取最优值。


      对于每个矩阵的分值而言,我们可以使用二维前缀和进行预处理。


       CODE:

#include <bits/stdc++.h>//设dp[x1][y1][x2][y2][k]表示将左上角为(x1, y1), 右下角为(x2, y2) 的矩阵划分成k个小矩阵的最小x_i^2的累和值 
using namespace std;
const int M = 10, N = 20;
int n;
double dp[M][M][M][M][N], mp[M][M], sum[M][M], INF = 1e18;
void Get_sum(){//求二维前缀和
	for(int i = 1; i <= 8; i++){
		for(int j = 1; j <= 8; j++){
			sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + mp[i][j];
		}
	}
}

void pre_work(){//因为要求最小值,所以给DP数组附极大值
	for(int k = 1; k <= n; k++){
		for(int x1 = 1; x1 <= 8; x1++){
			for(int y1 = 1; y1 <= 8; y1++){
				for(int x2 = 1; x2 <=8; x2++){
					for(int y2 = 1; y2 <= 8; y2++){
						dp[x1][y1][x2][y2][k] = INF;
					}
				}
			}
		}
	}
}

double Get(int x1, int y1, int x2, int y2){//求左上角为(x1,x2)右下角为(x2,y2)的矩阵分值
	double x = sum[x2][y2] - sum[x1 - 1][y2] - sum[x2][y1 - 1] + sum[x1 - 1][y1 - 1];
	return x * x;//平方处理
}
int main(){
	scanf("%d", &n);
	for(int i = 1; i <= 8; i++){
		for(int j = 1; j <= 8; j++){
			scanf("%lf", &mp[i][j]);
		}
	}
	Get_sum();
	pre_work();
	double average = sum[8][8] / n;//平均数
	for(int k = 1; k <= n; k++){//阶段
		for(int x1 = 1; x1 <= 8; x1++){
			for(int y1 = 1; y1 <= 8; y1++){
				for(int x2 = x1; x2 <=8; x2++){
					for(int y2 = y1; y2 <= 8; y2++){
						double &p = dp[x1][y1][x2][y2][k];
						if(k == 1) p = Get(x1, y1, x2, y2);
						else{
							for(int row = x1 + 1; row <= x2; row++){//横截 //决策 
								p = min(p, dp[x1][y1][row - 1][y2][k - 1] + Get(row, y1, x2, y2));//要上 
								p = min(p, dp[row][y1][x2][y2][k - 1] + Get(x1, y1, row - 1, y2));//要下 
							}
							
							for(int line = y1 + 1; line <= y2; line++){//竖截 决策
								p = min(p, dp[x1][y1][x2][line - 1][k - 1] + Get(x1, line, x2, y2));//要左 
								p = min(p, dp[x1][line][x2][y2][k - 1] + Get(x1, y1, x2, line - 1));//要右 
							}							
						}
					}
				}
			}
		}
	}
	printf("%.3lf", sqrt(1.0 * (dp[1][1][8][8][n] - n * average * average) / n));//将dp[1][1][8][8][n]带回式子并求出答案
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值