【Poj 1191 棋盘分割】题解

题目链接

题目

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

原棋盘上每一格有一个分值,一块矩形棋盘的总分为其所含各格分值之和。现在需要把棋盘按上述规则分割成n块矩形棋盘,并使各矩形棋盘总分的均方差最小。
均方差,其中平均值,xi为第i块矩形棋盘的总分。
请编程对给出的棋盘及n,求出O'的最小值。

思路

化简式子可知原式是求:

\[\Large\sqrt{\frac{\sum_{i=1}^n x_i^2-\frac{(\sum_{i=1}^n x_i)^2}{n}}{n}} \]

\(\frac{(\sum_{i=1}^n x_i)^2}{n}\) 可以直接求出来,所以主要是弄前面一部分。

\(dp(lx, ly, rx, ry, k)\) 表示在 \((lx, ly)\)\((rx, ry)\) 的区间里分成 \(k\) 块每块的平方和最小值。

转移时可以考虑横切竖切的情况。

为了方便统计答案,上面的式子 \(\sqrt{\frac{\sum_{i=1}^n x_i^2-\frac{(\sum_{i=1}^n x_i)^2}{n}}{n}}\) 可以化简为:

\[\Large\sqrt{\frac{\sum_{i=1}^n x_i^2}{n}-(\frac{\sum_{i=1}^n x_i}{n})^2} \]

用记忆化搜索实现会更好。

Code

// Problem: 棋盘分割
// Contest: POJ - Noi 99
// URL: http://poj.org/problem?id=1191
// Memory Limit: 10 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

// #include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
#define int long long
inline int read(){int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;
ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+
(x<<3)+(ch^48);ch=getchar();}return x*f;}
//#define M
//#define mo
#define N 10
int n, m, i, j, k; 
int f[N][N][N][N][16]; 
int s[N][N], a[N][N], sigam[N][N][N][N]; 
double he; 

int sum(int lx, int ly, int rx, int ry)
{
	if(sigam[lx][ly][rx][ry]!=-1) return sigam[lx][ly][rx][ry]; 
	int Sum=s[rx][ry]-s[lx-1][ry]-s[rx][ly-1]+s[lx-1][ly-1]; 
	return sigam[lx][ly][rx][ry]=Sum*Sum; 
}

int dfs(int lx, int ly, int rx, int ry, int k)
{
	if(f[lx][ly][rx][ry][k]!=-1) return f[lx][ly][rx][ry][k]; 
	if(k==1) return f[lx][ly][rx][ry][k]=sum(lx, ly, rx, ry); 
	int ans=999999999999; 
	for(int i=lx; i<rx; ++i)
	{
		ans=min(ans, dfs(lx, ly, i, ry, k-1)+sum(i+1, ly, rx, ry)); 
		ans=min(ans, sum(lx, ly, i, ry)+dfs(i+1, ly, rx, ry, k-1)); 
	}
	for(int i=ly; i<ry; ++i)
	{
		ans=min(ans, dfs(lx, ly, rx, i, k-1)+sum(lx, i+1, rx, ry)); 
		ans=min(ans, sum(lx, ly, rx, i)+dfs(lx, i+1, rx, ry, k-1)); 
	}
	return f[lx][ly][rx][ry][k]=ans; 
}

signed main()
{
//	freopen("tiaoshi.in", "r", stdin); 
//	freopen("tiaoshi.out", "w", stdout); 
	while(scanf("%lld", &k)!=EOF)
	{
		memset(f, -1, sizeof(f)); 
		memset(sigam, -1, sizeof(sigam)); 
		memset(s, 0, sizeof(s)); 
		n=8; 
		for(i=1; i<=n; ++i)
			for(j=1; j<=n; ++j)
				a[i][j]=read(); 
		for(i=1; i<=n; ++i)
			for(j=1; j<=n; ++j)
				s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a[i][j]; 
		he=double(double(s[n][n])/double(k)); 
		// printf("%lld %lld %lf\n", dfs(1, 1, n, n, k), s[n][n], he); 
		printf("%.3f\n", sqrt(double(dfs(1, 1, n, n, k))/double(k)-he*he)); 
	}
	return 0; 
}

posted @ 2021-12-05 20:34  zhangtingxi  阅读(56)  评论(0编辑  收藏  举报