1191 棋盘分割

#include < iostream >
#include < cmath >
#define INF 10000000
using   namespace std;

const   int m =   8 ;
int a[ 10 ][ 10 ];
int n;
double dp[ 16 ][ 10 ][ 10 ][ 10 ][ 10 ], s[ 10 ][ 10 ][ 10 ][ 10 ];

/**/ /*
dp[k][x1][y1][x2][y2]:左上角坐标为(x1,y1),右下角坐标为(x2,y2)
的棋盘,设它把切割k次以后得到的k+1块矩形的总分平方和最小值.

s[x1][y1][x2][y2]:左上角坐标为(x1,y1),右下角坐标为(x2,y2)
的棋盘的总和的平方


dp[k][x1][y1][x2][y2] =
1)按横的划分:    min(dp[k-1][x1][y1][f][y2]+s[f+1][y1][x2][y2]
                , dp[k-1][f+1][y1][x2][y2]+s[x1][y1][f][y2]);

2)按竖的划分:    min(dp[k-1][x1][y1][x2][f]+s[x1][f+1][x2][y2]
                , dp[k-1][x1][f+1][x2][y2]+s[x1][y1][x2][f]);
*/

double mmin( double a, double b)
{
     return a < b ? a: b;
}

int main()
{
     // freopen("data.txt", "r", std);

     int x1, y1, x2, y2, t, f;
     double sum, average, temp;
     while (cin >> n) {
        sum =   0 ;
         for (x1 =   0 ; x1 < m; x1 ++ )
             for (y1 =   0 ; y1 < m; y1 ++ ) {
                cin >> a[x1][y1];
                sum += a[x1][y1];
            }
        average = sum / n;
   // 计算s[x1][y1][x2][y2] 没有平方只是简单的和而已
         for (x1 =   0 ; x1 < m; x1 ++ ) {
             for (y1 =   0 ; y1 < m; y1 ++ ) {
                 for (x2 = x1; x2 < m; x2 ++ ) {
                    sum =   0 ;
                     for (y2 = y1; y2 < m; y2 ++ ) {
                        sum += a[x2][y2];
                         if (x1 == x2)
                            s[x1][y1][x2][y2] = sum;
                         else
                            s[x1][y1][x2][y2] = s[x1][y1][x2 - 1 ][y2] + sum;
                    }
                }
            }
        }
   // 进行初始列的初始化工作不抛弃不放弃继续continue的向前工作
          for (x1 =   0 ; x1 < m; x1 ++ ) {
             for (y1 =   0 ; y1 < m; y1 ++ ) {
                 for (x2 = x1; x2 < m; x2 ++ ) {
                     for (y2 = y1; y2 < m; y2 ++ ) {
                        s[x1][y1][x2][y2] *= s[x1][y1][x2][y2];
                        dp[ 0 ][x1][y1][x2][y2] = s[x1][y1][x2][y2];
                    }
                }
            }
        }

          for (t =   1 ; t < n; t ++ ) {
             for (x1 =   0 ; x1 < m; x1 ++ ) {
                 for (y1 =   0 ; y1 < m; y1 ++ ) {
                     for (x2 = x1; x2 < m; x2 ++ ) {
                         for (y2 = y1; y2 < m; y2 ++ ) {
                            dp[t][x1][y1][x2][y2] = INF;
                             for (f = x1; f < x2; f ++ ) {
                                temp = mmin(dp[t - 1 ][x1][y1][f][y2] + s[f + 1 ][y1][x2][y2]
                                    , dp[t - 1 ][f + 1 ][y1][x2][y2] + s[x1][y1][f][y2]);
                                dp[t][x1][y1][x2][y2] = mmin(temp, dp[t][x1][y1][x2][y2]);
                            }
                              for (f = y1; f < y2; f ++ ) {
                                temp = mmin(dp[t - 1 ][x1][y1][x2][f] + s[x1][f + 1 ][x2][y2]
                                    , dp[t - 1 ][x1][f + 1 ][x2][y2] + s[x1][y1][x2][f]);
                                dp[t][x1][y1][x2][y2] = mmin(temp, dp[t][x1][y1][x2][y2]);
                            }
                        }
                    }
                }
            }
        }
       
         double ans;
        ans = dp[n - 1 ][ 0 ][ 0 ][m - 1 ][m - 1 ] / n - average * average;
        printf( "%.3llf/n " , sqrt(ans));
}
return   0 ;

<think>好的,用户想了解棋盘分割的相关概念或实现方法。首先我需要回忆相关的知识,然后结合提供的引用内容来组织回答。 根据引用[1]和[2],棋盘分割问题是将8x8的棋盘分割成n块矩形,使得各块总分的均方差最小。这应该是一个动态规划问题,因为需要最优子结构。用户提到的均方差最小化是关键,需要计算所有可能的分割方式,找到最优解。动态规划的状态可能需要记录当前分割的矩形区域和分割次数,转移方程可能涉及不同切割方式的选择。 引用[3]和[4]讨论的是棋盘覆盖问题,使用分治法处理L型骨牌覆盖,这虽然也是棋盘相关,但和用户的问题不同。用户的问题更偏向于分割棋盘以优化均方差,所以需要区分这两个问题,避免混淆。 用户可能想知道具体的算法步骤,比如如何建模、状态转移方程、初始化等。需要解释动态规划的状态定义,比如dp[k][x1][y1][x2][y2]表示将区域(x1,y1)-(x2,y2)分割k次的最小平方和。然后如何通过横向和纵向切割来转移状态。 另外,需要提到预处理二维前缀和,这样可以快速计算任意矩形的总分。这在动态规划中是关键步骤,能提高效率。 代码实现方面,可能需要用多维数组存储状态,循环遍历分割次数和所有可能的矩形区域。引用[2]提到C++实现,但用户可能需要Python的例子,不过根据问题描述,示例代码可能较复杂,但可以给出伪代码或步骤说明。 还要注意问题中的约束条件,比如每次分割必须沿格子边,分割后的剩余部分也必须是矩形。因此每次切割只能将一个大矩形分成两个较小的矩形,这会影响状态转移的方式。 最后,用户可能想知道算法的时间复杂度和优化方法,比如如何减少状态数或使用记忆化技术。但因为问题规模是8x8,所以动态规划在合理时间内可行。 总结回答结构:定义问题,动态规划思路,状态转移方程,预处理前缀和,复杂度分析,应用场景。然后生成相关问题。</think>### 棋盘分割算法实现解析 棋盘分割的核心目标是**将棋盘分割成n块矩形,使各块总分值的均方差最小**,属于动态规划与数学优化的结合问题[^1][^2]。 --- #### 一、问题定义与数学模型 1. **输入**:8×8棋盘,每个格子分值$v_{i,j}$,分割次数$n-1$(最终得到n块) 2. **目标**:最小化均方差: $$ \sigma = \sqrt{\frac{\sum_{i=1}^{n}(X_i - \bar{X})^2}{n}} $$ 其中$X_i$为第i块总分,$\bar{X} = \frac{\sum X_i}{n}$为平均值 --- #### 二、动态规划实现步骤 1. **预处理二维前缀和** 计算$sum[x][y]$表示左上角(1,1)到(x,y)的矩形总分: $$ sum[i][j] = sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1] + v_{i,j} $$ 2. **状态定义** $dp[k][x_1][y_1][x_2][y_2]$表示将矩形$(x_1,y_1)-(x_2,y_2)$分割k次的最小平方和 3. **状态转移方程** - **横向切割**:遍历切割位置$x \in [x_1, x_2)$ $$ dp[k][x_1][y_1][x_2][y_2] = \min\left(dp[k-1][x_1][y_1][x][y_2] + calc(x+1,y_1,x_2,y_2)\right) $$ - **纵向切割**:遍历切割位置$y \in [y_1, y_2)$ $$ dp[k][x_1][y_1][x_2][y_2] = \min\left(dp[k-1][x_1][y_1][x_2][y] + calc(x_1,y+1,x_2,y_2)\right) $$ 4. **初始化** 未分割时($k=0$)的平方和为当前矩形总分平方: $$ dp[0][x1][y1][x2][y2] = (sum[x2][y2] - sum[x1-1][y2] - sum[x2][y1-1] + sum[x1-1][y1-1])^2 $$ --- #### 三、关键代码逻辑(伪代码) ```python # 预处理前缀和 sum = [[0]*9 for _ in range(9)] for i in 1..8: for j in 1..8: sum[i][j] = sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1] + v[i][j] # 动态规划初始化 dp = 四维数组 for x1 in 1..8: for y1 in 1..8: for x2 in x1..8: for y2 in y1..8: s = sum[x2][y2] - sum[x1-1][y2] - sum[x2][y1-1] + sum[x1-1][y1-1] dp[0][x1][y1][x2][y2] = s*s # 状态转移 for k in 1..n-1: for x1 in 1..8: for y1 in 1..8: for x2 in x1..8: for y2 in y1..8: min_val = INF # 横向切割 for x in x1..x2-1: val = dp[k-1][x1][y1][x][y2] + calc(x+1,y1,x2,y2) min_val = min(min_val, val) # 纵向切割 for y in y1..y2-1: val = dp[k-1][x1][y1][x2][y] + calc(x1,y+1,x2,y2) min_val = min(min_val, val) dp[k][x1][y1][x2][y2] = min_val # 最终结果计算 total = sum[8][8] mean = total / n result = sqrt(dp[n-1][1][1][8][8]/n - mean*mean) ``` --- #### 四、算法特性 1. **时间复杂度**:$O(n \cdot 8^6)$,因四重矩形循环($8^4$)乘以分割次数$n$ 2. **空间优化**:可复用滚动数组减少空间占用[^2] 3. **应用场景**:图像分块压缩、资源分配优化等需要最小化区域差异的场景 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值