洛谷 P1436 棋盘分割 题解

题目链接

 

 

 

题解

 

一道区间dp好题

用f[x1][y1][x2][y2][k]状态表示:

1) 集合:划分到k−1个的子矩阵,是以(x1,y1)为左上角,(x2,y2)为右下角

2) 属性:平方和的最大值

 

我们按照每次分割作为状态划分依据;

模拟上述集合的划分枚举所有的区间即可

由于维数较大,五重循环过于麻烦,所以这道题我们采用记忆化搜索;

 

代码

 

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>

using namespace std;

const int N = 15,M = 9;
const int INF = 1e9;
int  f[M][M][M][M][N];

int s[N][N],n,m = 8;

int get(int x1,int y1,int x2,int y2)
{
    int sum = s[x2][y2] - s[x1 - 1][y2] - s[x2][y1 - 1] + s[x1 - 1][y1 - 1];
    return  sum * sum;
    
}

int  dp(int x1, int y1, int x2, int y2, int k)
{
    int &v = f[x1][y1][x2][y2][k];
    if (v >= 0) return v;
    if (k == 1) return v = get(x1, y1, x2, y2);

    v = INF;
    for (int i = x1; i < x2; i ++ )
    {
        v = min(v, get(x1, y1, i, y2) + dp(i + 1, y1, x2, y2, k - 1));
        v = min(v, get(i + 1, y1, x2, y2) + dp(x1, y1, i, y2, k - 1));
    }

    for (int i = y1; i < y2; i ++ )
    {
        v = min(v, get(x1, y1, x2, i) + dp(x1, i + 1, x2, y2, k - 1));
        v = min(v, get(x1, i + 1, x2, y2) + dp(x1, y1, x2, i, k - 1));
    }

    return v;
}

int main()
{
    cin >> n;
    for (int i = 1; i <= m; i ++ )
        for (int j = 1; j <= m; j ++ )
        {
            cin >> s[i][j];
            s[i][j] += s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1];
        }
    memset(f, -1, sizeof f);
    printf("%d", (dp(1, 1, 8, 8, n)));

    return 0;
}

 

posted @ 2021-04-09 12:22  Linyk  阅读(47)  评论(0编辑  收藏  举报