NOI 1999 POJ 1191 棋盘分割 二维平面上的区间DP

版权声明:https://blog.csdn.net/huashuimu2003 https://blog.csdn.net/huashuimu2003/article/details/88927510

title

POJ 1191
CH POJ1191
Description

将一个8*8的棋盘进行如下分割:将原棋盘割下一块矩形棋盘并使剩下部分也是矩形,再将剩下的部分继续如此分割,这样割了(n-1)次后,连同最后剩下的矩形棋盘共有n块矩形棋盘。(每次切割都只能沿着棋盘格子的边进行)
在这里插入图片描述
原棋盘上每一格有一个分值,一块矩形棋盘的总分为其所含各格分值之和。现在需要把棋盘按上述规则分割成n块矩形棋盘,并使各矩形棋盘总分的均方差最小。
均方差 σ = Σ i = 1 n ( x i x ) 2 n \sigma =\sqrt {\dfrac {\Sigma ^{n}_{i=1}\left( x_{i}-\overline {x}\right) ^{2}}{n }} ,其中平均值 x = Σ i = 1 n x i n \overline {x}=\dfrac {\Sigma ^{n}_{i=1}x_{i}}{n} ,xi为第i块矩形棋盘的总分。
请编程对给出的棋盘及n,求出O’的最小值。

Input

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

Output

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

Sample Input

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

Sample Output

1.633

Source

扫描二维码关注公众号,回复: 5722535 查看本文章

Noi 99

analysis

NOI1999的dp都好厉害呀= =
一定要认真读题!
先看这个均方差的式子,可以进行化简:

σ = i = 1 n ( x i x ) 2 n \sigma =\sqrt {\dfrac {\sum ^{n}_{i=1}\left( x_{i}-\overline {x}\right) ^{2}}{n }}
σ 2 = i = 1 n ( x i x ) 2 n \sigma^{2} =\dfrac {\sum ^{n}_{i=1}\left( x_{i}-\overline {x}\right) ^{2}}{n }
= 1 n i = 1 n ( x i 2 2 x i x + x 2 ) =\dfrac {1}{n}\sum ^{n}_{i=1}\left( x^{2}_{i}-2x_{i}\overline {x}+\overline {x}^{2}\right)
= 1 n i = 1 n x i 2 1 n i = 1 n 2 x i x + 1 n i = 1 n x 2 =\dfrac {1}{n}\sum ^{n}_{i=1}x^{2}_{i}-\dfrac {1}{n}\sum ^{n}_{i=1}2x_{i}\overline {x}+\dfrac {1}{n}\sum ^{n}_{i=1}\overline {x}^{2}
= 1 n i = 1 n x i 2 2 x 1 n i = 1 n x i + 1 n i = 1 n x 2 =\dfrac {1}{n}\sum ^{n}_{i=1}x^{2}_{i}-2\overline {x}\dfrac {1}{n}\sum ^{n}_{i=1}x_{i}+\dfrac {1}{n}\sum ^{n}_{i=1}\overline {x}^{2}
= 1 n i = 1 n x i 2 x 2 =\dfrac {1}{n}\sum ^{n}_{i=1}x^{2}_{i}-\overline {x}^{2}
显然 1 n \dfrac {1}{n} x 2 \overline {x}^{2} 都是定值,那么我们的任务是求 i = 1 n x i 2 \sum ^{n}_{i=1}x^{2}_{i} 的最小值。

f [ i ] [ x 1 ] [ y 1 ] [ x 2 ] [ y 2 ] f[i][x1][y1][x2][y2] 表示切第i刀,剩余的矩形左上角和右下角的坐标是 ( x 1 , y 1 ) (x1,y1) ( x 2 , y 2 ) (x2,y2) ,除了剩余部分其它部分的 x i xi 平方和的最小值。那么 f ( i ) f(i) 可以向 f ( i + 1 ) f(i+1) 转移,只需要暴力枚举第 i + 1 i+1 刀从哪里切了一刀即可。
矩阵前缀和搞的时候细节比较多,一定要细心。

wrong reason

在状态转移时,我竟然把 f [ i ] [ x 1 ] [ y 1 ] [ x 2 ] [ y 2 ] f[i][x1][y1][x2][y2] 写成了 f [ i ] [ x 1 ] [ x 2 ] [ y 1 ] [ y 2 ] f[i][x1][x2][y1][y2] ,竟然还能过掉两个样例。。。。。。。。。。。抵制手残!!!!!!

code

#include<bits/stdc++.h>
using namespace std;
const int inf=1e9+7;
template<typename T>inline void read(T &x)
{
	x=0;
	T f=1, ch=getchar();
	while (!isdigit(ch) && ch^'-') ch=getchar();
	if (ch=='-') f=-1, ch=getchar();
	while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
	x*=f;
}
int a[10][10],w[10][10];
double f[20][10][10][10][10];
double ans,sum;
inline double add(int x1,int y1,int x2,int y2)
{
	double ww=w[x2][y2]-w[x1-1][y2]-w[x2][y1-1]+w[x1-1][y1-1]-sum;
	return ww*ww;
}
int main()
{
	int n;read(n);
	sum=0;
	for (int i=1; i<=8; ++i)
		for (int j=1; j<=8; ++j)
			read(a[i][j]),sum+=a[i][j];
	sum=sum/n;
	for (int i=1; i<=8; ++i)
		for (int j=1; j<=8; ++j)
			w[i][j]=w[i-1][j]+w[i][j-1]-w[i-1][j-1]+a[i][j];
	for (int i=0; i<=n; ++i)
		for (int x1=1; x1<=8; ++x1)
			for (int y1=1; y1<=8; ++y1)
				for (int x2=x1; x2<=8; ++x2)
					for (int y2=y1; y2<=8; ++y2)
						f[i][x1][y1][x2][y2]=inf;
	f[0][1][1][8][8]=0;
	for (int i=1; i<n; ++i)
		for (int x1=1; x1<=8; ++x1)
			for (int y1=1; y1<=8; ++y1)
				for (int x2=x1; x2<=8; ++x2)
					for (int y2=y1; y2<=8; ++y2)
						for (int j=1; j<=8; ++j)
						{
							if (x1-j>0)
								f[i][x1][y1][x2][y2]=min(f[i-1][x1-j][y1][x2][y2]+add(x1-j,y1,x1-1,y2),f[i][x1][y1][x2][y2]);
							if (y1-j>0)
								f[i][x1][y1][x2][y2]=min(f[i-1][x1][y1-j][x2][y2]+add(x1,y1-j,x2,y1-1),f[i][x1][y1][x2][y2]);
							if (x2+j<=8)
								f[i][x1][y1][x2][y2]=min(f[i-1][x1][y1][x2+j][y2]+add(x2+1,y1,x2+j,y2),f[i][x1][y1][x2][y2]);
							if (y2+j<=8)
								f[i][x1][y1][x2][y2]=min(f[i-1][x1][y1][x2][y2+j]+add(x1,y2+1,x2,y2+j),f[i][x1][y1][x2][y2]);
						}
	ans=inf;
	for (int x1=1; x1<=8; ++x1)
		for (int y1=1; y1<=8; ++y1)
			for (int x2=x1; x2<=8; ++x2)
				for (int y2=y1; y2<=8; ++y2)
					if (f[n-1][x1][y1][x2][y2]+add(x1,y1,x2,y2)<ans)
						ans=f[n-1][x1][y1][x2][y2]+add(x1,y1,x2,y2);
	ans=ans/n;
	ans=sqrt(ans);
	printf("%.3f\n",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/huashuimu2003/article/details/88927510