poj1191-dp棋盘分割

来源:互联网 发布:python gmail发送邮件 编辑:程序博客网 时间:2024/04/29 22:07

点击打开链接

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

这题要很好的空间想象力,开了一个五维数组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:bint 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;}





原创粉丝点击