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

原棋盘上每一格有一个分值,一块矩形棋盘的总分为其所含各格分值之和。
现在需要把棋盘按上述规则分割成 n 块矩形棋盘,并使各矩形棋盘总分的均方差最小。
均方差
,其中平均值
,xi 为第 i 块矩形棋盘的总分。
请编程对给出的棋盘及 n,求出均方差的最小值。
输入格式
第 1 行为一个整数 n。
第 2 行至第 9 行每行为 8 个小于 100 的非负整数,表示棋盘上相应格子的分值。每行相邻两数之间用一个空格分隔。
输出格式
输出最小均方差值(四舍五入精确到小数点后三位)。
数据范围
1<n<15
输入样例:
输出样例:
解题思路
区间dp
二维平面上的区间dp:
-
状态表示:f[x1][y1][x2][y2][k] 表示左上角为 (x1,y1),右上角为 (x2,y2) 的子矩阵含有 k 个小矩阵的最小 ∑(xi−X)2n,其中 X 为整个矩阵分为 n 块的平均值
-
状态计算,令 t=f[x1][y1][x2][y2][k],其中 get 函数获取矩阵面积:
-
横向切:
-
- t=min(t,dp(i+1,y1,x2,y2,k−1)+get(x1,y1,i,y2))
-
- t=min(t,dp(x1,y1,i,y2,k−1)+get(i+1,y1,x2,y2))
-
纵向切:
-
- t=min(t,dp(x1,i+1,x2,y2,k−1)+get(x1,y1,x2,i))
-
- t=min(t,dp(x1,y1,x2,i,k−1)+get(x1,i+1,x2,y2))
-
时间复杂度:(n×85)
代码
#include <bits/stdc++.h>
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template <typename T> void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
const int N=16,M=9;
int n;
double f[M][M][M][M][N],s[M][M],X=0;
double get(int x1,int y1,int x2,int y2)
{
double sum=s[x2][y2]-s[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1];
sum-=X;
return sum*sum/n;
}
double dp(int x1,int y1,int x2,int y2,int k)
{
double &t=f[x1][y1][x2][y2][k];
if(t>=0)return t;
if(k==1)return t=get(x1,y1,x2,y2);
t=2e9;
for(int i=x1;i<x2;i++)
{
t=min(t,dp(i+1,y1,x2,y2,k-1)+get(x1,y1,i,y2));
t=min(t,dp(x1,y1,i,y2,k-1)+get(i+1,y1,x2,y2));
}
for(int i=y1;i<y2;i++)
{
t=min(t,dp(x1,i+1,x2,y2,k-1)+get(x1,y1,x2,i));
t=min(t,dp(x1,y1,x2,i,k-1)+get(x1,i+1,x2,y2));
}
return t;
}
int main()
{
cin>>n;
for(int i=1;i<M;i++)
for(int j=1;j<M;j++)
{
cin>>s[i][j];
X+=s[i][j];
s[i][j]+=s[i-1][j]+s[i][j-1]-s[i-1][j-1];
}
X/=n;
memset(f,-1,sizeof f);
printf("%.3lf",sqrt(dp(1,1,8,8,n)));
return 0;
}
__EOF__
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!