acm pku 1191 棋盘分割(多维dp)
联立题目给的两个式子,化简之后,就可以得到题目要求的就是每块子棋盘的平方和最小。
F = MIN{ SUM(Xi2)i=1…n }
对于一个棋盘,可以横着切割,也可以竖直切割。切割完,会得到两块子棋盘,如果此时还切不够n次的话,就继续递归,对两块子棋盘进行切割,找出最小的切割方式。
子棋盘的最小分割导致整个棋盘的最小分割,符合最优子结构。
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
double f[10][10][10][10][20];
double s[10][10][10][10];
double a[10][10];
double cal(int i1,int j1,int i2,int j2) //计算某一矩形和的平方
{
if(s[i1][j1][i2][j2]>=0)
return s[i1][j1][i2][j2];
int i,j;
double sum=0;
for(i=i1;i<=i2;i++)
{
for(j=j1;j<=j2;j++)
{
sum+=a[i][j];
}
}
s[i1][j1][i2][j2]=sum*sum;
return s[i1][j1][i2][j2];
}
double ge(int i1,int j1,int i2,int j2,int k)
{
if(k==1)
return cal(i1,j1,i2,j2);
if(f[i1][j1][i2][j2][k]>=0)
return f[i1][j1][i2][j2][k];
int i,j;
double ff=0;
double mini=999999999999999;
for(i=i1;i<i2;i++) //横切
{
ff=__min((ge(i1,j1,i,j2,k-1)+cal(i+1,j1,i2,j2)),(ge(i+1,j1,i2,j2,k-1)+cal(i1,j1,i,j2)));
//按横切分成两部分后,下一步是分割上面的矩形还是分割下面的矩形,在两者之间作出决策,哪个和更小,选哪个
if(ff<mini)
mini=ff;
}
for(j=j1;j<j2;j++) //纵切
{
ff=__min((ge(i1,j1,i2,j,k-1)+cal(i1,j+1,i2,j2)),(ge(i1,j+1,i2,j2,k-1)+cal(i1,j1,i2,j)));
if(ff<mini)
mini=ff;
}
f[i1][j1][i2][j2][k]=mini;
return f[i1][j1][i2][j2][k];
}
int main()
{
double n;
int i,j;
double x;
double min=0;
double sum=0;
scanf("%lf",&n);
memset(a,0,sizeof(a));
memset(f,-1,sizeof(f));
memset(s,-1,sizeof(s));
for(i=1;i<=8;i++)
{
for(j=1;j<=8;j++)
{
scanf("%lf",&a[i][j]);
sum+=a[i][j];
}
}
x=sum/n;
min=ge(1,1,8,8,n);
printf("%.3lf\n",sqrt(min/n-(x*x)));
return 0;
}
浙公网安备 33010602011771号