【动态规划+递归】:poj1191,棋盘分割

http://poj.org/problem?id=1191



明白几点:

1)最终的均方差可以转变成:sqrt( sigma[ i:1-m ]( xi*xi ) / n - ( sum(all) / n )*( sum(all) / n ) ),不懂这个转换的需要补一下数学基础;所以最终决定最小值的是sigma[ i:1-m ]( xi*xi )。

2)动归含义:

dp[n][x1][x2][y1][y2]
表示由x1,x2,y1,y2组成的矩形要生成n块小矩阵,均方差的最小值(sigma[ i:1-m ]( xi*xi ));它的值需要遍历所有横向切、纵向切的可能,然后取最小值。最终结果是dp[n][1][8][1][8],不多说。




# include<iostream>
# include<string.h>
# include<cmath>
using namespace std;

# define N 16
# define INF 1000000000

int data[9][9];
int dp[N][9][9][9][9];
int onePart[9][9][9][9];


int OnePart(int x1, int x2, int y1, int y2)
{
	int sum=0;

	for(int x=x1;x<=x2;x++)
	{
		for(int y=y1;y<=y2;y++)
		{
			sum+=data[x][y];
		}
	}

	return sum;
}


int Partition(int n, int x1, int x2, int y1, int y2)
{
	if(dp[n][x1][x2][y1][y2]!=-1)
	{
		return dp[n][x1][x2][y1][y2];
	}
	else
	{
		int x,y,t,t1,t2;

		dp[n][x1][x2][y1][y2]=INF;
		//up-down
		for(x=x1;x<x2;x++) //x<x2, not x<=x2
		{
			//continue partition up
			t1=onePart[x+1][x2][y1][y2]+Partition(n-1,x1,x,y1,y2); //onePart[x+1][x2][y1][y2], not onePart[x][x2][y1][y2]
			//continue partition down
			t2=onePart[x1][x][y1][y2]+Partition(n-1,x+1,x2,y1,y2);
			t = t1<t2? t1:t2 ;
			dp[n][x1][x2][y1][y2] = dp[n][x1][x2][y1][y2]<t? dp[n][x1][x2][y1][y2]:t ;
		}
		//left-right
		for(y=y1;y<y2;y++)
		{
			//continue partition left
			t1=onePart[x1][x2][y+1][y2]+Partition(n-1,x1,x2,y1,y);
			//continue partition right
			t2=onePart[x1][x2][y1][y]+Partition(n-1,x1,x2,y+1,y2);
			t = t1<t2? t1:t2 ;
			dp[n][x1][x2][y1][y2] = dp[n][x1][x2][y1][y2]<t? dp[n][x1][x2][y1][y2]:t ;
		}

		return dp[n][x1][x2][y1][y2];
	}
}


int main()
{
	int x1,x2,y1,y2,x,y,n,t;
	int sum=0;

	cin>>n;

	for(x=1;x<=8;x++)
	{
		for(y=1;y<=8;y++)
		{
			cin>>data[x][y];
			sum+=data[x][y];
		}
	}

	memset(dp,-1,sizeof(dp));
	
	for(x1=1;x1<=8;x1++)
	{
		for(x2=x1;x2<=8;x2++)
		{
			for(y1=1;y1<=8;y1++)
			{
				for(y2=y1;y2<=8;y2++)
				{
					t=OnePart(x1,x2,y1,y2);
					onePart[x1][x2][y1][y2]=t*t;
					dp[1][x1][x2][y1][y2]=t*t;
				}
			}
		}
	}

	Partition(n,1,8,1,8);

	printf("%.3f\n",  sqrt( dp[n][1][8][1][8]*1.0/n - (sum*1.0/n)*(sum*1.0/n) )  );
	
	return 0;
}


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值