poj1191 2010.4.14
详解见黑书
#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
using namespace std;
#define MAXN 9
#define MAXT 16
#define M 8
#define MAX 9999999
int sum[MAXN][MAXN];
//sum[i][j],记录以 i行j列 为右下角,1行1列为左上角的方阵的和
double f[MAXT][MAXN][MAXN][MAXN][MAXN];
//f[k][x1][y1][x2][y2]:切k次后,得到的k+1块的总平方和的最小值
int n;
double ans;
//计算 (x1,y1)到(x2,y2)的格子的总和
int SUM(int xx1,int yy1,int xx2,int yy2)
{
int max=sum[xx2][yy2]-sum[xx2][yy1-1]-sum[xx1-1][yy2]+sum[xx1-1][yy1-1];
return max*max;
}
double min(double xx,double yy)
{
if (xx<yy)return xx;else return yy;
}
void init()
{
scanf("%d",&n);
int i,j,temp,s;
memset(sum,0,sizeof(sum));
for(i=1;i<=M;i++)
{
for(j=1,s=0;j<=M;j++)
{
scanf("%d",&temp);
s+=temp;
sum[i][j]=sum[i-1][j]+s;
}
}
}
void dpit()
{
memset(f,0,sizeof(f));
int xx1,xx2,yy1,yy2;
for(xx1=1;xx1<=M;xx1++)
{
for(yy1=1;yy1<=M;yy1++)
{
for(xx2=xx1;xx2<=M;xx2++)
{
for(yy2=yy1;yy2<=M;yy2++)
{
f[1][xx1][yy1][xx2][yy2]=SUM(xx1,yy1,xx2,yy2);
}
}
}
}
int i;
double tmp;
for(i=2;i<=n;i++)
{
for(xx1=1;xx1<=M;xx1++)
{
for(yy1=1;yy1<=M;yy1++)
{
for(xx2=xx1;xx2<=M;xx2++)
{
for(yy2=yy1;yy2<=M;yy2++)
{
f[i][xx1][yy1][xx2][yy2]=MAX;
for(int x=xx1;x<xx2;x++)
{
tmp=min(f[i-1][xx1][yy1][x][yy2]+SUM(x+1,yy1,xx2,yy2),f[i-1][x+1][yy1][xx2][yy2]+SUM(xx1,yy1,x,yy2));
if(f[i][xx1][yy1][xx2][yy2]>tmp)
f[i][xx1][yy1][xx2][yy2]=tmp;
}
for(int y=yy1;y<yy2;y++)
{
tmp=min(f[i-1][xx1][yy1][xx2][y]+SUM(xx1,y+1,xx2,yy2),f[i-1][xx1][y+1][xx2][yy2]+SUM(xx1,yy1,xx2,y));
if(f[i][xx1][yy1][xx2][yy2]>tmp)
f[i][xx1][yy1][xx2][yy2]=tmp;
}
}
}
}
}
}
}
int main()
{
init();
dpit();
ans=sqrt(f[n][1][1][8][8]/(double)n-sum[8][8]*sum[8][8]/(double)(n*n));
printf("%.3lf\n",ans);
return 0;
}