ACM模版

棋盘分割

参考题目链接:
POJ 1191 棋盘分割

/* * 棋盘分割 * 将一个8*8的棋盘进行如下分割:将原棋盘割下一块矩形棋盘并使剩下部 * 分也是矩形,再将剩下的部分继续如此分割,这样割了(n-1)次后,连同最 * 后剩下的矩形棋盘共有n块矩形棋盘。(每次切割都只能沿着棋盘格子的边 * 进行) 原棋盘上每一格有一个分值,一块矩形棋盘的总分为其所含各格分 * 值之和。现在需要把棋盘按上述规则分割成n块矩形棋盘,并使各矩形棋 * 盘总分的均方差最小。 均方差...,其中平均值...,xi为第i块矩形棋盘的 * 总分。请编程对给出的棋盘及 n,求出 O'的最小值。 */
#define min(a, b) ((a) < (b) ? (a) : (b))
const int oo = 10000000;

int map[8][8];
double C[16][8][8][8][8];   // c[k][si][ei][sj][ej]: 对矩阵
// map[si...sj][ei...ej]分割成k个矩形(切割k-1刀)的结果
double ans;                 // 平均值
int n;                      // 分成n块矩形棋盘

void input(void);
void reset(void);
double caluate(int i1, int j1, int i2, int j2);
void dp(int m, int si, int sj, int ei, int ej);

int main()
{
    int m, i, j, k, l;
    while (scanf("%d", &n) != EOF)
    {
        input();
        reset();
        for (m = 1; m <= n; m++)
        {
            for (i = 0; i < 8; i++)
            {
                for (j = 0; j < 8; j++)
                {
                    for (k = 0; k < 8; k++)
                    {
                        for (l = 0; l < 8; l++)
                        {
                            if ((k - i + 1) * (l - j + 1) < m)
                            {
                                C[m][i][j][k][l] = oo;
                            }
                            else
                            {
                                if (m == 1)
                                {
                                    C[m][i][j][k][l] = pow((caluate(i, j, k, l) - ans), 2);
                                }
                                else
                                {
                                    dp(m, i, j, k, l);
                                }
                            }
                        }
                    }
                }
            }
        }
        printf("%.3lf\n", sqrt(C[n][0][0][7][7] / n));
    }
    return 0;
}

void input()
{
    int i, j;
    double sum = 0;
    for (i = 0; i < 8; i++)
    {
        for (j = 0; j < 8; j++)
        {
            scanf("%d", &map[i][j]);
            sum += map[i][j];
        }
    }
    ans = sum / double(n);  // 平均值
}

void reset()
{
    int i, j, k, l, m;
    for (m = 0; m <= n; m++)
    {
        for (i = 0; i < 8; i++)
        {
            for (j = 0; j < 8; j++)
            {
                for (k = 0; k < 8; k++)
                {
                    for (l = 0; l < 8; l++)
                    {
                            C[m][i][j][k][l] = 0;
                    }
                }
            }
        }
    }
    return ;
}

double caluate(int i1, int j1, int i2, int j2)
{
    double sum = 0;
    int i, j;
    for (i = i1; i <= i2; i++)
    {
        for (j = j1; j <= j2; j++)
        {
            sum += map[i][j];
        }
    }
    return sum;
}

void dp(int m, int si, int sj, int ei, int ej)
{
    int i, j;
    double mins = oo;
    for (j = sj; j < ej; j++)
    {   // 竖刀
        mins = min(mins, C[1][si][sj][ei][j] + C[m - 1][si][j + 1][ei][ej]);
        mins = min(mins, C[m - 1][si][sj][ei][j] + C[1][si][j + 1][ei][ej]);
    }
    for (i = si; i < ei; i++)
    {   // 横刀
        mins = min(mins, C[1][si][sj][i][ej] + C[m - 1][i + 1][sj][ei][ej]);
        mins = min(mins, C[m - 1][si][sj][i][ej] + C[1][i + 1][sj][ei][ej]);
    }
    C[m][si][sj][ei][ej] = mins;
    return ;
}