321. 棋盘分割

题目链接

321. 棋盘分割

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

原棋盘上每一格有一个分值,一块矩形棋盘的总分为其所含各格分值之和。

现在需要把棋盘按上述规则分割成 \(n\) 块矩形棋盘,并使各矩形棋盘总分的均方差最小。

均方差image,其中平均值image\(x_i\) 为第 i 块矩形棋盘的总分。

请编程对给出的棋盘及 \(n\),求出均方差的最小值。

输入格式

\(1\) 行为一个整数 \(n\)

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

输出格式

输出最小均方差值(四舍五入精确到小数点后三位)。

数据范围

\(1<n<15\)

输入样例:

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

解题思路

区间dp

二维平面上的区间dp:

  • 状态表示:\(f[x_1][y_1][x_2][y_2][k]\) 表示左上角为 \((x_1,y_1)\),右上角为 \((x_2,y_2)\) 的子矩阵含有 \(k\) 个小矩阵的最小 \(\frac{\sum(x_i-X)^2}{n}\),其中 \(X\) 为整个矩阵分为 \(n\) 块的平均值

  • 状态计算,令 \(t=f[x_1][y_1][x_2][y_2][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\times 8^5)\)

代码

// Problem: 棋盘分割
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/description/323/
// Memory Limit: 10 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

// %%%Skyqwq
#include <bits/stdc++.h>
 
//#define int long long
#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;
}
posted @ 2022-03-16 13:13  zyy2001  阅读(40)  评论(0编辑  收藏  举报