poj1191解题报告

【题意简述】

给定一个8*8的正方形区域,将他们划分为n块,得到n个权值和,求出这n个权值和的均方差最小值。

【思考方向】

DP

【思路叙述】

为了叙述方便,我们设

        观察题目中的公式,我们发现只需求出的最小值,再除以n开根号即可。

        我们进行展开:

         

由于Sum为定值,问题转化为求n块子区域权值和的平方和最小值。

确定状态:设dp[ax][ay][bx][by][t]为

把左上角坐标为(ax,ay),右下角坐标为(bx,by)

的子区域分为t块,这t块区域的平方和。

初始化:递推求出所有矩形的权值和。

对于左上角坐标为(ax,ay),

右下角坐标为(bx,by)的矩形

有dp[ax][ay][bx][by][1] = sqr(add[ax][ay][bx][by])

即这个区域只分成了1块。

状态转移:

Case1:


Case2:


再注意一下t的值是由小到大递推即可。

下面是AC代码:

#include<cstdio>
#include<cstring>
#include<cmath>
inline int min(int a , int b)
{
	return a < b ? a : b;
}
inline int sqr(int x)
{
	return x * x;
}
int num[9][9];
int ans[9][9][9][9][15];
int sum_add[9][9][9][9];
int getadd(int xmin , int ymin , int xmax , int ymax)
{
	register int i,j;
	int add = 0;
	for(i = xmin ; i <= xmax ; ++i)
	for(j = ymin ; j <= ymax ; ++j)
	    add += num[i][j];
	return add;	
}
int main()
{
	register int i,j,k,l,m;
	int n;
	scanf("%d",&n);
	int sum = 0;
	for(i = 1 ; i <= 8 ; ++i)
	for(j = 1 ; j <= 8 ; ++j)
		scanf("%d",&num[i][j]) , sum += num[i][j];
	memset(ans , 0x3f , sizeof(ans));
	for(i = 1 ; i <= 8 ; ++i)
	for(j = 1 ; j <= 8 ; ++j)
	for(k = i ; k <= 8 ; ++k)
	for(l = j ; l <= 8 ; ++l)
	{
		sum_add[i][j][k][l] = getadd(i , j , k , l);
		ans[i][j][k][l][1] = sqr(sum_add[i][j][k][l]);
	}
	int level;
	int tmp;
	for(level = 2 ; level <= n ; ++level)
	{
		for(i = 1 ; i <= 8 ; ++i)
		for(j = 1 ; j <= 8 ; ++j)
		for(k = i ; k <= 8 ; ++k)
		for(l = j ; l <= 8 ; ++l)
		{
			for(m = j ; m < l ; ++m)
			{
				tmp = ans[i][j][k][m][level-1] + sqr(sum_add[i][m+1][k][l]);
				ans[i][j][k][l][level] = min(tmp , ans[i][j][k][l][level]);
				tmp = sqr(sum_add[i][j][k][m]) + ans[i][m+1][k][l][level-1];
				ans[i][j][k][l][level] = min(tmp , ans[i][j][k][l][level]);
			}
			for(m = i ; m < k ; ++m)
			{
				tmp = ans[i][j][m][l][level-1] + sqr(sum_add[m+1][j][k][l]);
				ans[i][j][k][l][level] = min(tmp , ans[i][j][k][l][level]);
				tmp = sqr(sum_add[i][j][m][l]) + ans[m+1][j][k][l][level-1];
				ans[i][j][k][l][level] = min(tmp , ans[i][j][k][l][level]);
			}
		}
	}
	printf("%.3f",sqrt((ans[1][1][8][8][n] - sum * sum / double(n)) / double(n)));
	return 0;
}
终于大功告成。。。

蒟蒻写题解难免有错误,请大家批评指出。

Thanks!

     

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值