棋盘分割

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 ;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值