1191:棋盘分割,考点:递归条件

原题:http://bailian.openjudge.cn/practice/1191/

描述

将一个8*8的棋盘进行如下分割:将原棋盘割下一块矩形棋盘并使剩下部分也是矩形,再将剩下的部分继续如此分割,这样割了(n-1)次后,连同最后剩下的矩形棋盘共有n块矩形棋盘。(每次切割都只能沿着棋盘格子的边进行)

 

 原棋盘上每一格有一个分值,一块矩形棋盘的总分为其所含各格分值之和。现在需要把棋盘按上述规则分割成n块矩形棋盘,并使各矩形棋盘总分的均方差最小。
均方差,其中平均值,xi为第i块矩形棋盘的总分。
请编程对给出的棋盘及n,求出O'的最小值。

输入

第1行为一个整数n(1 < n < 15)。
第2行至第9行每行为8个小于100的非负整数,表示棋盘上相应格子的分值。每行相邻两数之间用一个空格分隔。

输出

仅一个数,为O'(四舍五入精确到小数点后三位)。

样例输入

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

解法

首先对均方差的公式进行分析,简化要算的内容。

 

设置递归函数func(n,x1,y1,x2,y2)表示以(x1,y1)为左上角,(x2,y2)为右下角的棋盘分割成n份后的最小平方和。从n-1份到n份有横着切、竖着切两种。

横着切:上半部分的左上角仍为(x1,y1),右下角为(i,y2);下半部分的左上角为(i+1,y1),右下角为(x2,y2)。n-1份可以在上半部分,也可以在下半部分。

竖着切:左半部分的左上角仍为(x1,y1),右下角为(x2,j);右半部分的左上角为(x1,j+1),右下角为(x2,y2)。n-1份可以在左半部分,也可以在右半部分。

递归边界:无法继续切的时候

 

 为了避免TLE,用一个表fval来记录中间结果。(动规)

坑:算平均值的时候用double而不是int,不然会WA

 1 #include <iostream>
 2 #include <cstring>
 3 #include <iomanip>
 4 #include <cmath>
 5 #define INF 1<<30
 6 using namespace std;
 7 int chess[8][8];
 8 int fval[15][8][8][8][8];
 9 int func(int n, int x1, int y1, int x2, int y2) {
10     if (fval[n][x1][y1][x2][y2] != -1)
11         return fval[n][x1][y1][x2][y2];
12     if (x2 - x1 + y2 - y1 < n - 1) {
13         fval[n][x1][y1][x2][y2] = INF;
14         return INF;
15     }
16     if (n == 1) {
17         int sum = 0;
18         for(int i=x1;i<=x2;i++)
19             for (int j = y1; j <= y2; j++) {
20                 sum += chess[i][j];
21             }
22         fval[n][x1][y1][x2][y2] = sum * sum;
23         return sum * sum;
24     }
25     int mmin = INF;
26     for (int i = x1; i < x2; i++) {
27         int temp = func(n - 1, x1, y1, i, y2) + func(1, i + 1, y1, x2, y2);
28         if (temp < mmin)mmin = temp;
29         temp = func(1, x1, y1, i, y2) + func(n - 1, i + 1, y1, x2, y2);
30         if (temp < mmin)mmin = temp;
31     }
32     for (int j = y1; j < y2; j++) {
33         int temp = func(n - 1, x1, y1, x2, j) + func(1, x1, j + 1, x2, y2);
34         if (temp < mmin)mmin = temp;
35         temp = func(1, x1, y1, x2, j) + func(n - 1, x1, j + 1, x2, y2);
36         if (temp < mmin)mmin = temp;
37     }
38     fval[n][x1][y1][x2][y2] = mmin;
39     return mmin;
40 }
41 int main()
42 {
43     int n;
44     int sum = 0;
45     cin >> n;
46     for (int i = 0; i < 8; i++)
47         for (int j = 0; j < 8; j++)
48         {
49             cin >> chess[i][j];
50             sum += chess[i][j];
51         }
52     memset(fval, -1, sizeof(fval));
53     int square = func(n, 0, 0, 7, 7);
54     double avg = (double)sum / n;//注意这里一定要转换成double,不然会WA
55     double result = square - n * avg*avg;
56     cout << fixed << setprecision(3) << sqrt(result / n) << endl;
57     return 0;
58 }

 

posted @ 2021-07-09 11:06  永远是个小孩子  阅读(70)  评论(0编辑  收藏  举报