用汉字写的题目,不容小视。
这题要很好的空间想象力,开了一个五维数组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;
}