poj1191-dp棋盘分割

点击打开链接

用汉字写的题目,不容小视。

这题要很好的空间想象力,开了一个五维数组dp[k][x][y][xx][yy],表示把对角线为(x,y)-(xx,yy)的矩形分割成k块能获得的最小值。

先看问题,要我们求方差;

如果不化解,有点无从下手.可以为S^2=(1/n)∑xi^2+x^2,  (xi表示每个矩形的权值,x 是平均值。)

而对于一个给定的棋盘平均值是确定的。要求最小,只要求前面一个最小,求前面最小,只要求每个矩形的最小权值最小就行了。毫无疑问,

这题用dp可以实现。我们知道,棋盘可以沿着水平反向和垂直方向割。所以动态方程就为:

                   沿着x轴有:        dp[k][x][y][xx][yy]=min(DP(k+1,i,y,xx,yy)+sum[k+1][x][y][i+1][yy],DP(k+1,x,y,i+1,yy)+sum[i][y][xx][yy]);

                   沿着y轴有:        dp[k][x][y][xx][yy]=min(DP(k+1,x,y,xx,i)+sum[x][i+1][xx][y], DP(k+1,x,i+1,xx,yy)+sum[x][y][xx][i]);

自己没这个能力写出来,看牛人的。

唉。。。。。。。。。

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

int map[9][9],dp[16][9][9][9][9];
int g[9][9][9][9],n;

void init()   //求每个矩形的权值的平方和。
{
	int x,y,xx,yy,i,j; 
	for(x=0;x<9;x++)
	for(y=0;y<9;y++){
		for(xx=x;xx<9;xx++)
		for(yy=y;yy<9;yy++){
			int ans=0;
			for(i=x;i<=xx;i++)
			for(j=y;j<=yy;j++){
				ans+=map[i][j];
			}
			g[x][y][xx][yy]=ans*ans;   //四维数组,很难想的到。
			g[xx][y][x][yy]=ans*ans;
			g[x][yy][xx][y]=ans*ans;
			g[xx][yy][x][y]=ans*ans;
		}
	}
}

int DP(int k,int x,int y,int xx,int yy)
{
	int i,ans=0;
	if(dp[k][x][y][xx][yy]>=0) return dp[k][x][y][xx][yy];
	if(k==n-1) return g[x][y][xx][yy];
	dp[k][x][y][xx][yy]=1<<29;
	for(i=x;i<xx;i++){
		ans=min(DP(k+1,x,y,i,yy)+g[i+1][y][xx][yy],DP(k+1,i+1,y,xx,yy)+g[x][y][i][yy]);  
        dp[k][x][y][xx][yy]=min(ans,dp[k][x][y][xx][yy]);  
	}
	for(i=y;i<yy;i++){
		ans=min(DP(k+1,x,y,xx,i)+g[x][i+1][xx][yy],DP(k+1,x,i+1,xx,yy)+g[x][y][xx][i]);
		dp[k][x][y][xx][yy]=min(ans,dp[k][x][y][xx][yy]);
	}
	return dp[k][x][y][xx][yy];
}

int main()
{
	int i,j,res=0;
	double ans;
	scanf("%d",&n);
	for(i=0;i<8;i++)
	for(j=0;j<8;j++){
		scanf("%d",&map[i][j]);
		res+=map[i][j];
	}
	init();
	memset(dp,-1,sizeof(dp));
	DP(0,0,0,7,7);
	ans=sqrt((dp[0][0][0][7][7])*1.0/n-(res*1.0/n)*(res*1.0/n)); 
	printf("%.3lf\n",ans); 
	return 0;
}





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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值