[BZOJ1048][HAOI2007]分割矩阵(数学相关+记搜)

来源:互联网 发布:java前端和后端的区别 编辑:程序博客网 时间:2024/04/30 21:08

题目描述

传送门

题目大意:给出一个n*m的棋盘,每一个格子有一个权,切n-1刀,变成n个子矩形,每一个子矩形的权为所有格子的权值和,求一种方案使这些子矩形的均方差最小。

题解

均方差的化简方法同棋盘分割:http://blog.csdn.net/clove_unique/article/details/52936610
f(i,a,b,c,d)表示还有i刀可切,当前的矩形为(a,b,c,d)的最小值
由于切开的两个矩形都可以再切,写记搜方便一些

代码

#include<algorithm>#include<iostream>#include<cstring>#include<cstdio>#include<cmath>using namespace std;#define N 15int x,y,n,inf,Min,s[N][N],f[N][N][N][N][N];double xba,ans;int qr(int x){return x*x;}int dp(int id,int a,int b,int c,int d){    int re=f[id][a][b][c][d];    if (re!=inf) return re;    for (int mid=a;mid<c;++mid)        for (int i=0;i<id;++i)        {            int p=dp(i,a,b,mid,d);            int q=dp(id-1-i,mid+1,b,c,d);            if (p!=inf&&q!=inf) re=min(re,p+q);        }    for (int mid=b;mid<d;++mid)        for (int i=0;i<id;++i)        {            int p=dp(i,a,b,c,mid);            int q=dp(id-1-i,a,mid+1,c,d);            if (p!=inf&&q!=inf) re=min(re,p+q);        }    f[id][a][b][c][d]=re;    return re;}int main(){    scanf("%d%d%d",&x,&y,&n);;    for (int i=1;i<=x;++i)        for (int j=1;j<=y;++j)        {            int x;scanf("%d",&x);            s[i][j]=s[i][j-1]+s[i-1][j]-s[i-1][j-1]+x;        }    memset(f,127,sizeof(f));inf=f[0][0][0][0][0];    for (int a=1;a<=x;++a)        for (int b=1;b<=y;++b)            for (int c=a;c<=x;++c)                for (int d=b;d<=y;++d)                    f[0][a][b][c][d]=qr(s[c][d]-s[c][b-1]-s[a-1][d]+s[a-1][b-1]);    Min=dp(n-1,1,1,x,y);    xba=(double)s[x][y]/(double)n;    ans=(double)Min/(double)n-xba*xba;    printf("%.2lf\n",sqrt(ans));}
0 0