本文来自我的洛谷博客

这个题解思路虽然与其他人的思路相同,

但力求使用清晰易懂的图片和文字,讲解最简洁的道理。

请大家耐心地看完,注意要结合图片一起哦~~

2022-8-24 更改了格式与错别字。

2022-8-28 更改了数学公式格式。

这是本蒟蒻第一次写题解,不足之处请多包涵。


题目大意:

读完题的可以跳过这一部分。

给定一个矩阵,每个位置上都有数字。

可以分割 \(n-1\) 次,每次分割为 \(2\) 个矩形,然后把一半放在一旁,然后在另外一半继续割。

像这样:

可以横切也可以纵切。

样例给的很好。

然后就分为 \(n\) 块(因为割了 \(n-1\) 次)。

记 \(X=\dfrac{s}{n}\),\(s\) 为矩阵中所有的数字之和。

设第 \(i\) 块的和为 \(x_i\),那么求出怎样割才能使 $\sum_{i=1}{n}(x_i-X)2 $ 更小。


分析问题:

我们看到这种分割问题,最后组合起来求总体最优值,便可以立马联想到区间 DP。这叫望梅止渴做 DP 问题的复杂反射。

毕竟区间 DP 的主要思想就是大区间包含小区间,

小区间汇集成大区间。

好了,废话不多说,我们先从如下几个角度思考:

  • 状态表示
  • 状态含义
  • 目标状态
  • 状态转移

一、状态表示:\(f(x1,y1,x2,y2,k)\)。

二、状态含义:\(f(x1,y1,x2,y2,k)\) 表示求解子矩阵 \((x1,y1)\sim(x2,y2)\) 割了 \(k\) 刀得来的最优解(即下图框住区域的最优解)。

三、目标状态:\(f(1,1,8,8,n)\),即求解整个矩阵被割了 \(n\) 刀的最优解。

四、状态转移:

我们以下图为例,讲解 \(f(x1,y1,x2,y2,k)\) 是如何被拆分的。

①:考虑选择上面继续割(如下图),丢掉下面的,其分界线为第 \(i\) 行。

所以应该取上面的最优值,同时少割一刀:\(f(x1,y1,i,y2,k-1)\),

而下面的部分为定值:\(\dfrac{(sum-X)^2}{n}\)。

\(sum\) 为下面的部分所有格子的和。

这两个部分合起来就是 \(f(x1,y1,x2,y2,k)\)。


②:考虑选择下面继续割(如上图)。

上面部分的定值:\(\dfrac{(sum-X)^2}{n}\)。

下面的最优值:\(f(i+1,y1,x2,y2,k-1)\)。

\(sum\) 为上面的部分所有格子的和。


下面考虑纵切。

③:考虑选择左边继续割(如上图),分界线为第 \(i\) 列。

取左边的最优值:\(f(x1,y1,x2,i,k-1)\),

右边的部分为定值:\(\dfrac{(sum-X)^2}{n}\)。

\(sum\) 为右边的部分所有格子的和。


④:考虑选择右边继续割(如上图)。

取右边的最优值:\(f(x1,i+1,x2,y2,k-1)\),

左边的部分为定值:\((sum-X)\times(sum-X)/n\),

\(sum\) 为左边的部分所有格子的和。


我们每次取一个值,其实都是在将问题规模缩小。

情况考虑清楚了,那怎么从一个 \(f\) 到另一个 \(f\) 呢,如果是用普通的区间 DP,那估计要使用 \(5\) 层甚至更多的循环,所以,我们使用万能的记忆化搜索,免去繁琐的循环结构。


综上所述,

我们便实现了对大区间的拆分。

而我们不断提到 \(sum\),是一块区域的和,那么,我们可以使用二维前缀和来维护。相信大家一定会。

好了,上 AC 代码。

#include <bits/stdc++.h>

using namespace std;

const int N=15;
const double INF=1e10; //因为要求min,所以要定义INF int n;
int m=8;
double X; //平均值
double s[N][N]; //记录每个格子的值
double f[N][N][N][N][N]; //状态 double GetSum(int x1,int y1,int x2,int y2)//求[x1,y1]~[x2,y2]的和,为下文的GetX服务
{
return s[x2][y2]-s[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1];
} double GetX(int x1,int y1,int x2,int y2)// 计算上文的(sum−X)×(sum−X)/n。
{
return (GetSum(x1,y1,x2,y2)-X)*(GetSum(x1,y1,x2,y2)-X)/n;
} double DFS(int x1,int y1,int x2,int y2,int k)//使用记忆化搜索进行递归调用
{
double& v=f[x1][y1][x2][y2][k];//因为太难写了,所以给f[x1][y1][x2][y2][k]建立引用
if(v>=0)return v; //已经访问过该点了,直接返回
if(k==1)return v=GetX(x1,y1,x2,y2);//最后一块,不可能再割了 v=INF; //为求最小值做准备 for(int i=x1;i<x2;i++) //下面是刚刚讨论的结果
{
v=min(v,DFS(x1,y1,i,y2,k-1)+GetX(i+1,y1,x2,y2));
v=min(v,DFS(i+1,y1,x2,y2,k-1)+GetX(x1,y1,i,y2));
} for(int i=y1;i<y2;i++)
{
v=min(v,DFS(x1,y1,x2,i,k-1)+GetX(x1,i+1,x2,y2));
v=min(v,DFS(x1,i+1,x2,y2,k-1)+GetX(x1,y1,x2,i));
} return v;
} int main()
{
scanf("%d",&n);
for(int i=1;i<=m;i++)
{
for(int j=1;j<=m;j++)
{
double x;
scanf("%lf",&x);
s[i][j]=s[i-1][j]+s[i][j-1]+x-s[i-1][j-1]; //建立前缀和
}
}
X=s[m][m]/n; //求平均值
memset(f,0x80,sizeof f); //初始化
printf("%.3f\n",sqrt(DFS(1,1,m,m,n)));//注意,一定要根号啊啊啊!!!
return 0;
}

P5752 [NOI1999] 棋盘分割题解的更多相关文章

  1. [NOI1999] 棋盘分割

    COGS 100. [NOI1999] 棋盘分割 http://www.cogs.pro/cogs/problem/problem.php?pid=100 ★★   输入文件:division.in  ...

  2. POJ1991 NOI1999棋盘分割

    棋盘分割 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 15581   Accepted: 5534 Description ...

  3. [NOI1999] 棋盘分割(推式子+dp)

    http://poj.org/problem?id=1191 棋盘分割 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 156 ...

  4. 【Luogu】P1436 棋盘分割 题解

    嗯,点开题目,哇!是一道闪亮亮的蓝题! 不要被吓到了,其实,这道题就是一个简单的DP啦! 我们设 \(f[x1][y1][x2][y2][c]\) 为以 \((x1,y1)\) 为左上角,以 \((x ...

  5. POJ 1191 棋盘分割

    棋盘分割 Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 11213 Accepted: 3951 Description 将一个 ...

  6. poj 1191 棋盘分割 动态规划

    棋盘分割 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 11457   Accepted: 4032 Description ...

  7. NOI 193棋盘分割.cpp

    193:棋盘分割 查看 提交 统计 提问 总时间限制:  1000ms 内存限制:  65536kB 描述 将一个8*8的棋盘进行如下分割:将原棋盘割下一块矩形棋盘并使剩下部分也是矩形,再将剩下的部分 ...

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

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

  9. POJ 1191棋盘分割问题

    棋盘分割问题 题目大意,将一个棋盘分割成k-1个矩形,每个矩形都对应一个权值,让所有的权值最小求分法 很像区间DP,但是也不能说就是 我们只要想好了一个怎么变成两个,剩下的就好了,但是怎么变,就是变化 ...

  10. 洛谷 P1436 棋盘分割 解题报告

    P1436 棋盘分割 题目描述 将一个8*8的棋盘进行如下分割:将原棋盘割下一块矩形棋盘并使剩下部分也是矩形,再将剩下的两部分中的任意一块继续如此分割,这样割了(n-1)次后,连同最后剩下的矩形棋盘共 ...

随机推荐

  1. day16:Linux常用命令

    Linux中目录含义 /bin 存放普通用户的命令文件/boot 存放系统启动文件/cdrom 存放读取光盘的相关文件/dev 设备文件 /etc 配置文件/home 家目录/lib 库文件/lib6 ...

  2. Typora用法:

    Typora用法: 一:标题 模板: #+空格+标题名+回车 一级标题 二级标题 三级标题 四级标题 五级标题 二:字体 加粗 斜体 斜体加粗 删除线(esc键下面的那个键) 上标:我是上标 下表:我 ...

  3. Mastering Regular Expressions(精通正则表达式) 阅读笔记:第一章,概念

    Real Scenario(现实场景) Here's the scenario: you're given the job of checking the pages on a web server ...

  4. 2022-12-31:以下go语言代码输出什么?A:1 1;B:-1 1;C:-1 -1;D:编译错误。 package main import “fmt“ func main() { a

    2022-12-31:以下go语言代码输出什么?A:1 1:B:-1 1:C:-1 -1:D:编译错误. package main import "fmt" func main() ...

  5. 2022-10-04:以下go语言代码输出什么?A:{123} main.T{x:123} B:{123} T{x:123} C:boo boo D:boo main.T{x:123}。 packag

    2022-10-04:以下go语言代码输出什么?A:{123} main.T{x:123} B:{123} T{x:123} C:boo boo D:boo main.T{x:123}. packag ...

  6. Python获取当前时间、获取当月第一天、最后一天日期等方法

    ```python先导入包: import calendarimport datetimefrom datetime import timedelta获取今天日期: #返回datetime格式:eg: ...

  7. Cannot apply DjangoModelPermissionsOrAnonReadOnly on a view that does not set `.queryset` or have a `.get_queryset()` method.

    这个问题是在使用 django REST 做自定义认证的时候出现的 解决方法是 在settings.py 中注释掉这个 REST_FRAMEWORK={ 'DEFAULT_PERMISSION_CLA ...

  8. ToolStrip1

    Private Sub ToolStrip1_ItemClicked(sender As Object, e As ToolStripItemClickedEventArgs) Handles Too ...

  9. React Native项目设置路径别名

    没有设置路径别名之前代码是这样的: import { px2dp } from '../../utils/screenKits'; 路径相当冗长,看着就头疼.增加了路径别名之后,变成这样 import ...

  10. springboot 静态资源导入

    1.根据源码可以看到需要去webjars官网下载jquery的依赖 <dependency> <groupId>org.webjars</groupId> < ...