[HAOI2007] 分割矩阵 - 记忆化搜索,dp

\(a\times b\) 的数字矩阵沿着数字间的缝隙做分割,分成 \(n\) 个矩形,每个矩形的分数是矩形内数字和,最小化各矩形分数的均方差。\(a,b,n \leq 10\)

Solution

均方差定义为
\[ s^2=\frac{1}{n}\sum_{i}(a_i-avg)^2=\frac{1}{n}\sum_{i=1}^n (a_i^2-avg^2)=\frac{1}{n}\sum_{i=1}^n a_i^2-\frac{S^2}{n^2} \]
于是就是要最小化 \(\sum a_i^2\)

\(f[i_1][j_1][i_2][j_2][k]\) 表示将矩形 \((i_1,j_1)-(i_2,j_2)\) 分割成 \(k\) 份,\(\sum a_i^2\) 的最小值

转移无非就是枚举分割线,记忆化搜索即可

矩形求和用二维前缀和预处理

时间复杂度 \(O(a^3b^3n^2)\)

#include <bits/stdc++.h>
using namespace std;

const int N = 12;
int a,b,n,s[N][N],f[N][N][N][N][N];

inline int get(int i,int j,int k,int l) {
    return s[k][l]-s[i-1][l]-s[k][j-1]+s[i-1][j-1];
}

inline int sh(int &x,int y) {
    x=min(x,y);
}

int dfs(int i1,int j1,int i2,int j2,int k) {
    if(f[i1][j1][i2][j2][k]<1e9) return f[i1][j1][i2][j2][k];
    for(int i=1;i<k;i++) {
        for(int j=i1;j<i2;j++) {
            sh(f[i1][j1][i2][j2][k],dfs(i1,j1,j,j2,i)+dfs(j+1,j1,i2,j2,k-i));
        }
        for(int j=j1;j<j2;j++) {
            sh(f[i1][j1][i2][j2][k],dfs(i1,j1,i2,j,i)+dfs(i1,j+1,i2,j2,k-i));
        }
    }
    return f[i1][j1][i2][j2][k];
}

signed main() {
    ios::sync_with_stdio(false);
    cin>>a>>b>>n;
    for(int i=1;i<=a;i++) {
        for(int j=1;j<=b;j++) {
            cin>>s[i][j];
            s[i][j]+=s[i-1][j]+s[i][j-1]-s[i-1][j-1];
        }
    }
    memset(f,0x3f,sizeof f);
    for(int i=1;i<=a;i++) {
        for(int j=1;j<=b;j++) {
            for(int k=i;k<=a;k++) {
                for(int l=j;l<=b;l++) {
                    f[i][j][k][l][1]=get(i,j,k,l)*get(i,j,k,l);
                }
            }
        }
    }
    int tmp = dfs(1,1,a,b,n);
    double ans = 1.0*tmp/n - 1.0*s[a][b]*s[a][b]/n/n;
    printf("%.2lf\n",(sqrt(ans)));
}

猜你喜欢

转载自www.cnblogs.com/mollnn/p/12381570.html