问题描述

将一个8*8的棋盘进行如下分割:将原棋盘割下一块矩形棋盘并使剩下部分也是矩形,再将剩下的部分继续如此分割,这样割了(n-1)次后,连同最后剩下的矩形棋盘共有n块矩形棋盘。(每次切割都只能沿着棋盘格子的边进行)

原棋盘上每一格有一个分值,一块矩形棋盘的总分为其所含各格分值之和。现在需要把棋盘按上述规则分割成n块矩形棋盘,并使各矩形棋盘总分的均方差最小。

均方差 ,其中平均值 ,x i为第i块矩形棋盘的总分。

请编程对给出的棋盘及n,求出O'的最小值。

输入格式

第1行为一个整数n(1 < n < 15)。

第2行至第9行每行为8个小于100的非负整数,表示棋盘上相应格子的分值。每行相邻两数之间用一个空格分隔。

输出格式

仅一个数,为O'(四舍五入精确到小数点后三位)。

样例输入输出

样例输入

3

1 1 1 1 1 1 1 3

1 1 1 1 1 1 1 1

1 1 1 1 1 1 1 1

1 1 1 1 1 1 1 1

1 1 1 1 1 1 1 1

1 1 1 1 1 1 1 1

1 1 1 1 1 1 1 0

1 1 1 1 1 1 0 3

样例输出

1.633

解析

首先,我们需要将均方差的公式进行一定的变形,方便进行动态规划。公式变形如下:

\[\begin{align}
\sigma &= \sqrt{\frac{\sum_{i=1}^n{(x_i-\overline{x})^2}}{n}}\\
&= \sqrt{\frac{\sum_{i=1}^n{(x_i^2-2x_i\overline{x}+\overline{x}^2)}}{n}}\\
&= \sqrt{\frac{\sum_{i=1}^n{x_i^2}-2\overline{x}\sum_{i=1}^nx_i+n\overline{x}}{n}}\\
&= \sqrt{\frac{\sum_{i=1}^n{x_i^2}}{n}-\overline{x}^2}
\end{align}
\]

那么,现在只与每个矩形的元素和的平方有关。矩阵的和可以用二位前缀和的方式来解决,下面的关键是如何用动态规划的方式解决这个问题。想要描述一个状态,显然需要知道当前剩余矩形的位置。另外,由于受切割次数的限制,还需要记录这个矩形是割了几次后的结果。由此,我们有如下动态规划策略:

设\(f[i][j]][k][l][d]\)表示在切割了d次后剩余的矩形左上角为(i,j)、右上角为(k,l)时的最优解。那么转移时可以由题目要求,从各个方向进行转移。方程因为太长,在代码里注释。代码里将\(f[i][j][k][l][0]\)设为矩形元素和的平方。

代码

#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
const int INF=1<<30;
int n, chess[9][9]={0}, sum[9][9]={0}, dp[9][9][9][9][15]={0};
//直接计算矩形(y1, x1)(y2, x2)矩形分数平方
int getX(int y1, int x1, int y2, int x2){
int a=sum[y2][x2]-sum[y2][x1-1]-sum[y1-1][x2]+sum[y1-1][x1-1];
return a*a;
}
int main(){
scanf("%d", &n);
//统一i表示y,j表示x
for(int i=1;i<=8;i++)
for(int j=1;j<=8;j++)
scanf("%d", &chess[i][j]);
//计算sum数组(矩形(1, 1)(i, j)的分数和),方便直接计算getX
for(int i=1;i<=8;i++){
for(int j=1;j<=8;j++)
sum[i][j]=sum[i][j-1]+chess[i][j];
for(int j=1;j<=8;j++)
sum[i][j]+=sum[i-1][j];
}
//初值
for(int i1=1;i1<=8;i1++)
for(int j1=1;j1<=8;j1++)
for(int i2=i1;i2<=8;i2++)
for(int j2=j1;j2<=8;j2++)
dp[i1][j1][i2][j2][0]=getX(i1, j1, i2, j2);
//这里的i是切割数(分析里的d)
for(int i=1;i<n;i++)
for(int i1=1;i1<=8;i1++)
for(int j1=1;j1<=8;j1++)
for(int i2=i1;i2<=8;i2++)
for(int j2=j1;j2<=8;j2++){
//赋值INF,若状态不合法不会干扰其他状态
dp[i1][j1][i2][j2][i]=INF;
//左右切割
for(int k=j1;k<j2;k++)
dp[i1][j1][i2][j2][i]=min(dp[i1][j1][i2][j2][i], min(dp[i1][j1][i2][k][i-1]+dp[i1][k+1][i2][j2][0], dp[i1][j1][i2][k][0]+dp[i1][k+1][i2][j2][i-1]));
//上下切割
for(int k=i1;k<i2;k++)
dp[i1][j1][i2][j2][i]=min(dp[i1][j1][i2][j2][i], min(dp[i1][j1][k][j2][i-1]+dp[k+1][j1][i2][j2][0], dp[i1][j1][k][j2][0]+dp[k+1][j1][i2][j2][i-1]));
}
//套公式
printf("%.3f\n", sqrt(double(dp[1][1][8][8][n-1])/n-double(sum[8][8]*sum[8][8])/n/n));
return 0;
}

[POJ 1911] 棋盘的更多相关文章

  1. POJ 1321 棋盘问题 --- DFS

    POJ 1321 题目大意:给定一棋盘,在其棋盘区域放置棋子,需保证每行每列都只有一颗棋子. (注意 .不可放 #可放) 解题思路:利用DFS,从第一行开始依次往下遍历,列是否已经放置棋子用一个数组标 ...

  2. HDU 2517 / POJ 1191 棋盘分割 区间DP / 记忆化搜索

    题目链接: 黑书 P116 HDU 2157 棋盘分割 POJ 1191 棋盘分割 分析:  枚举所有可能的切割方法. 但如果用递归的方法要加上记忆搜索, 不能会超时... 代码: #include& ...

  3. POJ 1191 棋盘分割 【DFS记忆化搜索经典】

    题目传送门:http://poj.org/problem?id=1191 棋盘分割 Time Limit: 1000MS   Memory Limit: 10000K Total Submission ...

  4. DFS POJ 1321 棋盘问题

    题目传送门 /* DFS:因为一行或一列都只放一个,可以枚举从哪一行开始放,DFS放棋子,同一列只能有一个 */ #include <cstdio> #include <algori ...

  5. POJ 1321 棋盘问题(C)回溯

    Emmm,我又来 POJ 了,这题感觉比上次做的简单点.类似皇后问题.但是稍微做了一点变形,比如棋子数量是不定的.棋盘形状不在是方形等等. 题目链接:POJ 1321 棋盘问题 解题思路 基本思路:从 ...

  6. OpenJudge/Poj 1321 棋盘问题

    1.链接地址: http://bailian.openjudge.cn/practice/1321 http://poj.org/problem?id=1321 2.题目: 棋盘问题 Time Lim ...

  7. OpenJudge/Poj 1191 棋盘分割

    1.链接地址: http://bailian.openjudge.cn/practice/1191/ http://poj.org/problem?id=1191 2.题目: 总时间限制: 1000m ...

  8. POJ 1321 棋盘问题(DFS板子题,简单搜索练习)

    棋盘问题 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 44012   Accepted: 21375 Descriptio ...

  9. POJ 1321 - 棋盘问题 - [经典DFS]

    题目链接:http://poj.org/problem?id=1321 Time Limit: 1000MS Memory Limit: 10000K Description 在一个给定形状的棋盘(形 ...

随机推荐

  1. VUE Right-hand side of ‘instanceof’ is not an object 解决方案

    这里要注意一下, props之前没注意写成了   props: {     wrd: '',       sname:'zs'   },   这样是不能被解析成object的,所以一定要写的更具体一点 ...

  2. OpenStack 多节点纳管 vCenter 5.5

    目录 目录 测试环境 Nova 配置OpenStack 纳管 vCenter 虚拟机 Glance 配置OpenStack 纳管 vCenter 镜像 Cinder 配置OpenStack 纳管 vC ...

  3. Delphi XE2 之 FireMonkey 入门(10) - 常用结构 TPoint、TPointF、TSmallPoint、TSize、TRect、TRectF 及相关方法

    它们都是结构, TPointF.TRectF 属新增, 其它也都有升级; 现在都拥有丰富的方法和方便的运算符重载; 且有一组相关的公共函数. 这组内容重要的是它们都来自 System.Types 单元 ...

  4. 测开之路九十:css的引用方式

    第一种:内联,直接在标签里面加style属性,优先级别最高,但是不利于维护 第二种:页面嵌入,在head标签里面写一个style标签,以类选择器的形式写入,优先级别第二 第三种:外联,样式表链接,单独 ...

  5. 剑指offer--day06

    1.1 题目:调整数组顺序使奇数位语偶数前面:输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的 ...

  6. vue子组件修改父组件传递过来的值

    这里不再赘述父子组件及子父组件传值,不懂的同学可以翻看我以前写过的关于两者传值的文章 父子组件传值:https://www.cnblogs.com/Sky-Ice/p/9267192.html 子父组 ...

  7. js获取select下拉框中的值

    现在有一id为userType的下拉框,怎么获取选中的值: 用户类型: <select name="type" id="userType"> < ...

  8. 红黑树的删除操作---以JDK源码为例

    删除操作需要处理的情况: 1.删除的是红色节点,则删除节点并不影响红黑树的树高,无需处理. 2.删除的是黑色节点,则删除后,删除节点所在子树的黑高BH将减少1,需要进行调整. 节点标记: 正在处理的节 ...

  9. struts框架中常用到的标签

    2.<constant name="struts.i18n.encoding" value="UTF-8" />     指定Web应用的默认编码集 ...

  10. idea / eclipse 批量 替换 空白行

    1.选择Regular expression项,允许查询匹配正则表达式 2.在Find文本框输入正则表达式:^\s*\n   , 点击ReplaceAll 转移字符 含义 ^ 否 * 0个或多个 \s ...