poj1191 棋盘分割 (DP)

题目链接:http://poj.org/problem?id=1191


//题目意思:在一个8*8的棋盘中要划分成n块,并且方差最小
//解题思路:用一个5维的数组来记录状态st[k][x1][y1][x2][y2],表示在第k次时从(x1,y1)到(x2,y2)的矩形切出的和的平方的和(就是已经分两块了,只是这个数组没表示从哪里切)。然后递归到前面一次,选择两个中的一块继续递归。

//0ms AC,代码如下:
#include<iostream>
#include<cstdio>
#include<math.h>
using namespace std;
#define min(a,b) ((a)<(b)) ? (a) : (b)


const int M =8;
int n;
int num[M+1][M+1]={0};//记录各个格子的值
int sum[M+1][M+1]={0};//记录(0,0)到(x,y)矩形的和
int st[15][M+1][M+1][M+1][M+1]; 

int sumFun(int x1,int y1,int x2,int y2)//返回矩形和的平方
{
	int temp;
	temp=sum[x2][y2]+sum[x1-1][y1-1]-sum[x1-1][y2]-sum[x2][y1-1];
	return temp*temp;
}
int dp(int k,int x1,int y1,int x2,int y2)
{
	int i,j,temp=1000000000;
	if(st[k][x1][y1][x2][y2]!=-1)//已计算过了不用再算
		return st[k][x1][y1][x2][y2];
	else if(k==1||x1==x2||y1==y2)
	{
		return st[k][x1][y1][x2][y2]=sumFun(x1,y1,x2,y2);
	}
	else 
	{
		for(i=x1;i<x2;i++)
		{
			temp=min(temp,min(sumFun(i+1, y1, x2, y2)+dp(k-1, x1, y1, i, y2),
				sumFun(x1, y1, i, y2)+dp(k-1, i+1, y1, x2, y2)));
		}
		for(j=y1;j<y2;j++)
		{
			temp=min(temp, min(dp(k-1, x1, y1, x2, j)+sumFun(x1, j+1, x2, y2), 
				dp(k-1, x1, j+1, x2, y2)+sumFun(x1, y1, x2, j)));
		}
		st[k][x1][y1][x2][y2]=temp;
	}
	return temp;
}
void init()
{
	scanf("%d",&n);
	int i,j;
	for(i=0;i<M+1;i++)
		for(j=0;j<M+1;j++)
		{
			if(i==0||j==0)
			{
				num[i][j]=0;
				sum[i][j]=0;
			}
			else 
			{
				scanf("%d",&num[i][j]);
				sum[i][j]=sum[i][j-1]+sum[i-1][j]-sum[i-1][j-1]+num[i][j];
			}
		}
}


void makeSt()//st的初始化
{
	int i,j,x,y,k;
	for(k=0;k<15;k++)
		for(i=0;i<=M;i++)
			for(j=0;j<=M;j++)
				for(x=0;x<=M;x++)
					for(y=0;y<=M;y++)
						st[k][i][j][x][y]=-1;
}

int main()
{
	init();
	makeSt();
	double res=(double)sqrt((double)dp(n,1,1,M,M)/(double)n
		-(double)pow((double)sqrt((double)sumFun(1,1,M,M))/(double)n,2.0));//之前因为没有强制转换为double,wa了好多次==!
	printf("%.3lf\n",res);
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值