【矩阵DP】BZOJ1048(HAOI2007)[分割矩阵]题解

题目概述

给出一个有权值的矩阵,一次操作将这个矩阵沿着行或列切成两半,然后这两半也可以执行同样的操作。操作 n1 n − 1 次后得到 n n 个矩阵,求这 n n 个矩阵的均方差(标准差?傻傻分不清啊QAQ)。

解题报告

五维DP f[i][j][x][y][k] f [ i ] [ j ] [ x ] [ y ] [ k ] 表示将矩阵 i i 行到 x x j j 列到 y y 列执行 k1 k − 1 次操作得到的最优解,转移的话就直接枚举在哪里切开,两边分别执行多少次操作。用记忆化搜索来写比较方便。

示例程序

#include
#include
#include
#include
using namespace std;
typedef long long LL;
const int maxn=10,maxk=10;

int n,m,K;LL f[maxn+5][maxn+5][maxn+5][maxn+5][maxk+5];
int all,sum[maxn+5][maxn+5];

inline LL sqr(LL x) {return x*x;}
#define val(i,j,x,y) sqr(sum[x][y]-sum[i-1][y]-sum[x][j-1]+sum[i-1][j-1]-all)
inline LL DP(int i,int j,int x,int y,int k){
    if (k==1) return val(i,j,x,y);if ((x-i+1)*(y-j+1)return 1e18;
    LL &now=f[i][j][x][y][k];if (~now) return now;now=1e18;
    for (int p=i;pfor (int t=1;t1,j,x,y,k-t));
    for (int p=j;pfor (int t=1;t1,x,y,k-t));
    return now;
}
int main(){
    freopen("program.in","r",stdin);
    freopen("program.out","w",stdout);
    scanf("%d%d%d",&n,&m,&K);memset(f,255,sizeof(f));
    for (int i=1;i<=n;i++)
        for (int j=1;j<=m;j++){
            scanf("%d",&sum[i][j]);all+=sum[i][j];
            sum[i][j]*=K;sum[i][j]+=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];
        }
    return printf("%.2f\n",sqrt((double)DP(1,1,n,m,K)/K/K/K)),0;
}

你可能感兴趣的:(BZOJ题解,区间DP,记忆化搜索)