棋盘分割
【题目描述】
将一个8*8的棋盘进行如下分割:将原棋盘割下一块矩形棋盘并使剩下部分也是矩形,再将剩下的部分继续如此分割,这样割了(n-1)次后,连同最后剩 下的矩形棋盘共有n块矩形棋盘。(每次切割都只能沿着棋盘格子的边进行)
原棋盘上每一格有一个分值,一块矩形棋盘的总分为其所含各格分值之和。现在需要把棋盘按上述规则分割成n块矩形棋盘,并使各矩形棋盘总分的均方差最小。
请编程对给出的棋盘及n,求出方差的最小值。
【输入描述】
第1行为一个整数n(1 < n < 15)。
第2行至第9行每行为8个小于 100 的非负整数,表示棋盘上相应格子的分值。每行相邻两数之间用一个空格分隔。
【输出描述】
仅一个数,为方差(四舍五入精确到小数点后三位)。
【样例输入】
3
1 1 1 1 1 1 1 3
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 0
1 1 1 1 1 1 0 3
【样例输出】
1.633
源代码: #include<cmath> #include<iostream> #include<iomanip> //包含【setprecision()】、【fixed】,用于四舍五入保留小数。 #define INF 1000000000 //定义极大值。 using namespace std; double n,num(0),ans,i[9][9]={0},sum[9][9]={0},f[16][9][9][9][9]; //皆为double类型,方便下面的计算。 int main() { cin>>n; //cin输入流。 int m=n; //作为int类型数组标志变量。 for (int a=1;a<=8;a++) for (int b=1;b<=8;b++) { cin>>i[a][b]; num+=i[a][b]; //总和。 sum[a][b]=sum[a][b-1]+sum[a-1][b]-sum[a-1][b-1]+i[a][b]; //计算[1][1][a][b]的矩形区间和。 } for (int a=1;a<=8;a++) for (int b=1;b<=8;b++) for (int c=a;c<=8;c++) for (int d=b;d<=8;d++) { double t; t=sum[c][d]-sum[c][b-1]-sum[a-1][d]+sum[a-1][b-1]; f[0][a][b][c][d]=t*t; //初始化f[切数][x1][y1][x2][y2]数组。 } for (int k=1;k<n;k++) //切了多少次。 for (int a=1;a<=8;a++) for (int b=1;b<=8;b++) for (int c=a;c<=8;c++) for (int d=b;d<=8;d++) { f[k][a][b][c][d]=INF; //初始化。 for (int t=a;t<c;t++) //横切。 { f[k][a][b][c][d]=min(f[k][a][b][c][d],f[0][a][b][t][d]+f[k-1][t+1][b][c][d]); f[k][a][b][c][d]=min(f[k][a][b][c][d],f[0][t+1][b][c][d]+f[k-1][a][b][t][d]); } for (int t=b;t<d;t++) //纵切。 { f[k][a][b][c][d]=min(f[k][a][b][c][d],f[0][a][b][c][t]+f[k-1][a][t+1][c][d]); f[k][a][b][c][d]=min(f[k][a][b][c][d],f[0][a][t+1][c][d]+f[k-1][a][b][c][t]); } } ans=f[m-1][1][1][8][8]/n-(num/n)*(num/n); //切的次数=矩形个数-1。 cout<<setprecision(3)<<fixed<<sqrt(ans); //亟待学习。 return 0; }