Poj 1191 棋盘分割

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

请编程对给出的棋盘及n,求出O'的最小值。

思路:lrj《算法与信息学竞赛》中P116的例题。dp[k][x1][y1][x2][y2]:左上角坐标为(x1,y1),右下角坐标为(x2,y2)
的棋盘,设它把切割k次以后得到的k+1块矩形的总分平方和最小值。
s[x1][y1][x2][y2]:左上角坐标为(x1,y1),右下角坐标为(x2,y2)。
的棋盘的总和的平方
状态转移方程dp[k][x1][y1][x2][y2] = 
1)按横的划分:    min(dp[k-1][x1][y1][f][y2]+s[f+1][y1][x2][y2] , dp[k-1][f+1][y1][x2][y2]+s[x1][y1][f][y2]);
2)按竖的划分:    min(dp[k-1][x1][y1][x2][f]+s[x1][f+1][x2][y2], dp[k-1][x1][f+1][x2][y2]+s[x1][y1][x2][f]);

/* 
dp[k][x1][y1][x2][y2]:左上角坐标为(x1,y1),右下角坐标为(x2,y2)
的棋盘,设它把切割k次以后得到的k+1块矩形的总分平方和最小值.

s[x1][y1][x2][y2]:左上角坐标为(x1,y1),右下角坐标为(x2,y2)
的棋盘的总和的平方


 dp[k][x1][y1][x2][y2] = 
1)按横的划分:    min(dp[k-1][x1][y1][f][y2]+s[f+1][y1][x2][y2]
                , dp[k-1][f+1][y1][x2][y2]+s[x1][y1][f][y2]);

2)按竖的划分:    min(dp[k-1][x1][y1][x2][f]+s[x1][f+1][x2][y2]
                , dp[k-1][x1][f+1][x2][y2]+s[x1][y1][x2][f]);
 */ 
#include <stdio.h>
#include <memory.h>
#include <math.h>
int n;
int dp[16][10][10][10][10];
int data[10][10];
int s[10][10][10][10];
void get_sum(int x1,int y1,int x2,int y2) {
	int i,j,sum;

	sum=0;

	if (s[x1][y1][x2][y2]!=0)
		return;
	for (i=x1;i<=x2;i++) {
		for (j=y1;j<=y2;j++) {
			sum=sum+data[i][j];
		}
	}
	s[x1][y1][x2][y2]=sum*sum;
}
int min_num(int a,int b) {
	if (a>b)
		return b;
	return a;
}
int main()
{
	int i,j,k,g,h,l,temp;
	double sum,average,result;

	scanf("%d",&n);
	sum=0;
	for (i=1;i<=8;i++) {
		for (j=1;j<=8;j++) {
			scanf("%d",&data[i][j]);
			sum+=data[i][j];
		}
	}
	average=sum/n;
	memset(s,0,sizeof(s));
	for (i=1;i<=8;i++) {
		for (j=1;j<=8;j++) {
			for (g=i;g<=8;g++) {
				for (h=j;h<=8;h++) {
					get_sum(i,j,g,h);
					dp[0][i][j][g][h]=s[i][j][g][h];

				}
			}
		}
	}
	for (k=1;k<n;k++) {
		for (i=1;i<=8;i++) {
			for (j=1;j<=8;j++) {
				for (g=i;g<=8;g++) {
					for (h=j;h<=8;h++) {
						dp[k][i][j][g][h]=10000000;
						for (l=i;l<g;l++) {
							get_sum(l+1,j,g,h);
							temp=min_num(dp[k-1][i][j][l][h]+s[l+1][j][g][h],dp[k-1][l+1][j][g][h]+s[i][j][l][h]);
							dp[k][i][j][g][h]=min_num(temp, dp[k][i][j][g][h]);
						}
						for (l=j;l<h;l++) {
							get_sum(i,l+1,g,h);
							temp=min_num(dp[k-1][i][j][g][l]+s[i][l+1][g][h],dp[k-1][i][l+1][g][h]+s[i][j][g][l]);
							dp[k][i][j][g][h]=min_num(temp, dp[k][i][j][g][h]);
						}
					}
				}
			}
		}
	}
	result=(double)dp[n-1][1][1][8][8]/n-average*average;
	printf("%.3lf\n",sqrt(result));
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值