POJ 1191 棋盘分割 DP

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


原棋盘上每一格有一个分值,一块矩形棋盘的总分为其所含各格分值之和。现在需要把棋盘按上述规则分割成n块矩形棋盘,并使各矩形棋盘总分的均方差最小。 
题解:主要弄明白均方差的转换公式即可。 刘汝佳书116页。

#include <cmath>
#include <iostream>
using namespace std;

#define N 9
#define INF 999999999
int s[N][N], dp[15][N][N][N][N];

int min ( int a, int b )
{
	return a < b ? a : b;
}

int count ( int k, int x1, int y1, int x2, int y2 )
{
	int c, ans = INF;
	for ( c = x1 + 1; c < x2; c++ )
	{
		ans = min ( dp[k-1][x1][y1][c][y2] + dp[0][c][y1][x2][y2], ans );
		ans = min ( dp[k-1][c][y1][x2][y2] + dp[0][x1][y1][c][y2], ans );
	}
	
	for ( c = y1 + 1; c < y2; c++ )
	{
		ans = min ( dp[k-1][x1][y1][x2][c] + dp[0][x1][c][x2][y2], ans );
		ans = min ( dp[k-1][x1][c][x2][y2] + dp[0][x1][y1][x2][c], ans );
	}
	return ans;
}

int main()
{
	int n, i, j, x1, y1, x2, y2, map, area;
	scanf("%d",&n);
	memset(s,0,sizeof(s));
	for ( i = 1; i <= 8; i++ )
	{
		for ( j = 1; j <= 8; j++ )
		{
			scanf("%d",&map);
			s[i][j] = s[i-1][j] + s[i][j-1] - s[i-1][j-1] + map;
		}
	}

	for ( x1 = 0; x1 < 8; x1++ )
	{
		for ( y1 = 0; y1 < 8; y1++ )
		{
			for ( x2 = x1+1; x2 <= 8; x2++ )
			{
				for ( y2 = y1+1; y2 <= 8; y2++ )
				{
					area = s[x2][y2] - s[x2][y1] - s[x1][y2] + s[x1][y1];
					dp[0][x1][y1][x2][y2] = area * area;
				}
			}
		}
	}

	for ( i = 1; i < n; i++ )
	{
		for ( x1 = 0; x1 < 8; x1++ )
		{
			for ( y1 = 0; y1 < 8; y1++ )
			{
				for ( x2 = x1+1; x2 <= 8; x2++ )
				{
					for ( y2 = y1+1; y2 <= 8; y2++ )
						dp[i][x1][y1][x2][y2] = count ( i, x1, y1, x2, y2 );
				}
			}
		}
	}

    double ans = dp[n-1][0][0][8][8] * 1.0 / n - pow ( s[8][8]*1.0/n, 2 );
	printf("%.3lf\n", sqrt(ans));
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值