POJ1191 棋盘分割

本文探讨了一种将8*8棋盘分割成n块矩形棋盘的方法,目标是使得各矩形棋盘总分的均方差最小。通过定义极差公式并推导转移方程,实现了一种动态规划算法来解决该问题。

题意:将一个8*8的棋盘进行如下分割:将原棋盘割下一块矩形棋盘并使剩下部分也是矩形,再将剩下的部分继续如此分割,这样割了(n-1)次后,连同最后剩下的矩形棋盘共有n块矩形棋盘。原棋盘上每一格有一个分值,一块矩形棋盘的总分为其所含各格分值之和。现在需要把棋盘按上述规则分割成n块矩形棋盘,并使各矩形棋盘总分的均方差最小。

 

根据定义

 

极差=  1/n *  (Σxi^2 - n*xba^2)  =Σxi^2/n  -xba^2

因为xba^2 =(整个矩形的权值/ N)^2

所以现在只要使Σxi^2 最大  即N个矩形的平方和最小

 

最后的状态:切割N-1次后,矩形0,0,8,8中的最小平方和

设状态数组 DP[17][9][9][9][9]  

有转移方程   DP[i][x1][y1][x2][y2] =   Min(   DP[i-1][a][y1][x2][y2] + S[x1][y1][a][y2]^2 ,

                                                                     DP[i-1][x1][y1][a][y2]+S[a][y1][x2][y2]^2 ,

                                                                     DP[i-1][x1][b][x2][y2]+S[x1][y1][x2][b]^2,

                                                                     DP[i-1][x1][y1][x2][b]+S[x1][b][x2][y2]^2

x1<a<=x2    ,y1<b<=y2

 

#include<stdio.h>
#include<string.h>
#include<math.h>
#define Min(a,b) (a<b?a:b)

int N;
int DP[16][9][9][9][9];
int Val[9][9];
int S[9][9];
float Averge2;

int main(){
	int i,j,x1,x2,y1,y2,a;
	int rowsum,temp;
	memset(DP,0,sizeof(DP));
	memset(S,0,sizeof(S));
	scanf("%d",&N);
	for(i=1;i<=8;i++)
		for(j=1;j<=8;j++)
			scanf("%d",&Val[i][j]);
	//Init左上角为00的所有矩形
	for(j=1;j<=8;j++)
		for(rowsum=0,i=1;i<=8;i++){
			rowsum+=Val[i][j];
			S[i][j]=S[i][j-1]+rowsum;
		}
	Averge2=(float)(S[8][8]*S[8][8])/(float)(N*N);
	for(i=0;i<=N-1;i++)
		for(x1=0;x1<=7;x1++)
			for(y1=0;y1<=7;y1++)
				for(x2=x1+1;x2<=8;x2++)
					for(y2=y1+1;y2<=8;y2++){
						if(i==0){
							DP[0][x1][y1][x2][y2]=(S[x2][y2]-S[x1][y2]-S[x2][y1]+S[x1][y1]);
							DP[0][x1][y1][x2][y2]=DP[0][x1][y1][x2][y2]*DP[0][x1][y1][x2][y2];
							continue;
						}
						DP[i][x1][y1][x2][y2]=100000000;
						for(a=x1;a<=x2;a++){
						    temp=(S[x2][y2]-S[x2][y1]-S[a][y2]+S[a][y1]);
						    temp=temp*temp;
							DP[i][x1][y1][x2][y2]=Min(DP[i-1][x1][y1][a][y2]+temp,DP[i][x1][y1][x2][y2]);
							temp=(S[a][y2]-S[a][y1]-S[x1][y2]+S[x1][y1]);
							temp=temp*temp;						    
							DP[i][x1][y1][x2][y2]=Min(DP[i-1][a][y1][x2][y2]+temp,DP[i][x1][y1][x2][y2]);
						}
						for(a=y1;a<=y2;a++){
						    temp=(S[x2][a]-S[x2][y1]-S[x1][a]+S[x1][y1]);
						    temp=temp*temp;
							DP[i][x1][y1][x2][y2]=Min(DP[i-1][x1][a][x2][y2]+temp,DP[i][x1][y1][x2][y2]);
						    temp=(S[x2][y2]-S[x2][a]-S[x1][y2]+S[x1][a]);
						    temp=temp*temp;
							DP[i][x1][y1][x2][y2]=Min(DP[i-1][x1][y1][x2][a]+temp,DP[i][x1][y1][x2][y2]);								
						}
						printf("DP[%d][%d][%d][%d][%d]=%d\n",i,x1,y1,x2,y2,DP[i][x1][y1][x2][y2]);
					}
	printf("%.3f\n",sqrt((float)DP[N-1][0][0][8][8]/N-Averge2));
	goto start;
	start:return 0;				
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值