洛谷P1436 棋盘分割 题解 二维区间DP

题目链接:https://www.luogu.com.cn/problem/P1436

这道题目和《算法艺术与信息学竞赛》的题目描述稍微有点区别(这里是求平方和的最小值,书上是方差的最小值),不过解法都是一样的,就是区间DP,我这里使用记忆化搜索实现。

\(f[r1][c1][r2][c2][m]\) 表示以 \((r1,c1)\) 为左上角的格子,以 \((r2,c2)\) 为右下角的格子,并且分成 \(m\) 份的最小平方和。

实现代码如下:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 10;
int n, a[maxn][maxn], low[maxn][maxn], sum[maxn][maxn];
int get_sum(int r1, int c1, int r2, int c2) {
    int t = sum[r2][c2] - sum[r1-1][c2] - sum[r2][c1-1] + sum[r1-1][c1-1];
    return t * t;
}
int f[maxn][maxn][maxn][maxn][15];
bool vis[maxn][maxn][maxn][maxn][15];
int solve(int r1, int c1, int r2, int c2, int m) {
    if (vis[r1][c1][r2][c2][m]) return f[r1][c1][r2][c2][m];
    vis[r1][c1][r2][c2][m] = true;
    if (m == 1) return f[r1][c1][r2][c2][m] = get_sum(r1, c1, r2, c2);
    if (r1 == r2 && c1 == c2) return f[r1][c1][r2][c2][m] = -1;
    int ans = -1;
    if (r1 < r2) {
        for (int i = r1; i < r2; i ++) {
            int tmp1 = solve(r1, c1, i, c2, 1);
            int tmp2 = solve(i+1, c1, r2, c2, m-1);
            if (tmp1 != -1 && tmp2 != -1) {
                if (ans == -1 || ans > tmp1 + tmp2) {
                    ans = tmp1 + tmp2;
                }
            }
        }
        for (int i = r1; i < r2; i ++) {
            int tmp1 = solve(r1, c1, i, c2, m-1);
            int tmp2 = solve(i+1, c1, r2, c2, 1);
            if (tmp1 != -1 && tmp2 != -1) {
                if (ans == -1 || ans > tmp1 + tmp2) {
                    ans = tmp1 + tmp2;
                }
            }
        }
    }
    if (c1 < c2) {
        for (int i = c1; i < c2; i ++) {
            int tmp1 = solve(r1, c1, r2, i, 1);
            int tmp2 = solve(r1, i+1, r2, c2, m-1);
            if (tmp1 != -1 && tmp2 != -1) {
                if (ans == -1 || ans > tmp1 + tmp2) {
                    ans = tmp1 + tmp2;
                }
            }
        }
        for (int i = c1; i < c2; i ++) {
            int tmp1 = solve(r1, c1, r2, i, m-1);
            int tmp2 = solve(r1, i+1, r2, c2, 1);
            if (tmp1 != -1 && tmp2 != -1) {
                if (ans == -1 || ans > tmp1 + tmp2) {
                    ans = tmp1 + tmp2;
                }
            }
        }
    }
    return f[r1][c1][r2][c2][m] = ans;
}
int main() {
    scanf("%d", &n);
    for (int i = 1; i <= 8; i ++) {
        for (int j = 1; j <= 8; j ++) {
            scanf("%d", &a[i][j]);
            low[i][j] = low[i][j-1] + a[i][j];
            sum[i][j] = sum[i-1][j] + low[i][j];
        }
    }
    printf("%d\n", solve(1, 1, 8, 8, n));
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/quanjun/p/13191278.html