解析:
对于此题,我们选择从方差的表达式入手,我们已知k是经过的点的数目,而到达重点是经过了(n+m-1)个点,令N=(n+m-1),此时x(即海拔)的平均值为(x1+x2+x3+…+xN)/N,(为了方便,用x_来代替x的平均值),σ^2=((x1-x_)^2+(x2-x_)^2+…+(xN-x_)^2)/N,
而最终答案(n+m-1)^2*σ^2=N^2*σ^2,将原式带入得到答案 ans=N*(x1^2+…+xN^2)-(x1+…+xN)^2。
具体过程如下:
N^2*σ^2
=N*((x1-x_)^2+…+(xN-x_)^2)
=N*((x1^2-2*x1*x_)^2+…+(xN^2-2*xN*x_+x_^2))
=N*((x1^2+…+xN^2)-2*x_*(x1+…+xN)+N*(x_^2))
然后再将x_=(x1+…+xN)/N带入,即可得到ans表达式。
易得,在某点的ans为 当前经过的点的数目乘以那些点的高度的平方的和 再减去它们的高度的和的平方。(有点儿绕)
因此我们可以设定一个DP状态f[i][j][k],k表示到达点(i,j)时,经过的点的高度的和(只是和,没有平方!)(包括(i,j)),f[i][j][k]的值则表示它们的高度的平方和。
因此动态转移方程为:
f[i][j][k]=min(f[i-1][j][k-h[i][j]],f[i][j-1][k-h[i][j]])+h[i][j]^2.
讲到这就差不多了,贴代码!!
#include<stdio.h>
#include<string.h>
int f[51][51][5100];
int h[51][51];
int min(int x,int y){
return x>=y?y:x;
}
int pf(int x){
return x*x;
}
int main(){
int n,m;
int i,j,k;
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
scanf("%d",&h[i][j]);
memset(f,-1,sizeof(f));
f[1][0][0]=f[0][1][0]=0;
for(i=1;i<=n;i++){
for(j=1;j<=m;j++){
int s=(i+j-1)*50; //高度和的上限
for(k=h[i][j];k<=s;k++){ //只是和,没有平方
if(f[i-1][j][k-h[i][j]]!=-1&&f[i][j-1][k-h[i][j]]!=-1) //左边和上边的点都可以更新当前的点
f[i][j][k]=min(f[i-1][j][k-h[i][j]],f[i][j-1][k-h[i][j]])+pf(h[i][j]);
else if(f[i-1][j][k-h[i][j]]!=-1) //只有左边的点可以
f[i][j][k]=f[i-1][j][k-h[i][j]]+pf(h[i][j]);
else if(f[i][j-1][k-h[i][j]]!=-1) //只有上边的点可以
f[i][j][k]=f[i][j-1][k-h[i][j]]+pf(h[i][j]);
}
}
}
int ans=1e9+9;
for(i=0;i<=(n+m-1)*50;i++)
if(f[n][m][i]!=-1)
ans=min(ans,(n+m-1)*f[n][m][i]-i*i);
printf("%d",ans); //直接代入公式 N*(x1^2+...+xN^2)-(x1+...+xN)^2
}