321. 棋盘分割(二维区间dp)

 321. 棋盘分割 - AcWing题库

题意

  • 一个矩阵可以横切,或者侧切,如图所示
  • 对于被切开成两个部分的棋盘,可以且只能选择一个继续向下切

求方差最小,由于均方差X固定,n固定,要计算的是被分成的子矩形的面积(xi-X)*(xi-X)。

所以,可以采用搜索的方法,不断地枚举出最小值

分析:二维区间dp,其实类似于数字三角形模型,由于分割可能不具有线性递推的关系,所以采用记忆化搜索的方法。

  • 横切i,分为两部分[(x1,y1)~(i,y2)],[(i+1,y2)~(x2,y2)]
  • 竖切i,分为两部分[(x1,y1)~(x2,i)],[(x2,i+1)~(x2,y2)]

初始化:全部初始化为无穷大,由于计划化搜索特殊性,所以先初始化为负数,进入是再初始化

状态转移方程/状态计算

根据横切竖切的位置i不同,和划分后继续划分哪个子集,可以划分为多个集合

横切,划分了两个子集,两个子集都可以继续划分,另一个直接计算

  • dp[x1][y1][x2][y2][k]=max(dp[x1][i][x2][y2][k]+sum[x1~i][y1~y2]);
  • dp[x1][y1][x2][y2][k]=max(dp[x1][y1][i+1][y2][k]+sum[i+1~]
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
const int N=16;
const int inf=1e9;
int s[N][N];
double dp[N][N][N][N][N];
double X;
double get(int x1,int y1,int x2,int y2)
{
    int a=s[x2][y2]-s[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1];
    return (a-X)*(a-X);
}
double dfs(int x1,int y1,int x2,int y2,int k)
{
    double &v=dp[x1][y1][x2][y2][k];//为了简便,加上v
    if(v>=0) return v;
    if(k==1) return get(x1,y1,x2,y2);
    v=1e9;  //求最小值,初始化为无穷
    
    for(int i=x1;i<x2;i++)
    {//横切的子集
        v=min(v,dfs(i+1,y1,x2,y2,k-1)+get(x1,y1,i,y2));
        v=min(v,dfs(x1,y1,i,y2,k-1)+get(i+1,y1,x2,y2));
    }
    
    for(int i=y1;i<y2;i++)
    {//竖切的子集
        v=min(v,dfs(x1,i+1,x2,y2,k-1)+get(x1,y1,x2,i));
        v=min(v,dfs(x1,y1,x2,i,k-1)+get(x1,i+1,x2,y2));
    }
    return v;
}
int main()
{
    int n;
    cin>>n;
    for(int i=1;i<=8;i++)
        for(int j=1;j<=8;j++)
            cin>>s[i][j];
    for(int i=1;i<=8;i++)
        for(int j=1;j<=8;j++)
            s[i][j]+=s[i][j-1]+s[i-1][j]-s[i-1][j-1];
    
    X=(double)s[8][8]/n;
    memset(dp,-1,sizeof dp);    //由于积分可能是0,所以取-1
    double a=dfs(1,1,8,8,n)/n;
    printf("%.3lf",sqrt(a));
    return 0;    
}

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值