BZOJ1048:[HAOI2007]分割矩阵(记忆化搜索DP)

Description

将一个a*b的数字矩阵进行如下分割:将原矩阵沿某一条直线分割成两个矩阵,再将生成的两个矩阵继续如此分割(当然也可以只分割其中的一个),

这样分割了(n-1)次后,原矩阵被分割成了n个矩阵。(每次分割都只能沿着数字间的缝隙进行)

原矩阵中每一位置上有一个分值,一个矩阵的总分为其所含各位置上分值之和。

现在需要把矩阵按上述规则分割成n个矩阵,并使各矩阵总分的均方差最小。请编程对给出的矩阵及n,求出均方差的最小值。

Input

第一行为3个整数,表示a,b,n(1<a,b<=10,1<n<=10)的值。
第二行至第n+1行每行为b个小于100的非负整数,表示矩阵中相应位置上的分值。每行相邻两数之间用一个空格分开。

Output

仅一个数,为均方差的最小值(四舍五入精确到小数点后2位)

Sample Input

5 4 4
2 3 4 6
5 7 5 1
10 4 0 5
2 0 2 3
4 1 1 1

Sample Output

0.50

Solution

平均值一开始可以直接算,然后直接记忆化搜索就好了。
$f[a][b][c][d][k]$表示左上角为$(a,b)$,右下角为$(c,d)$的矩形被划分了$k$次后的最小答案。

Code

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<cmath>
 5 #define N (12)
 6 using namespace std;
 7 
 8 double ave,f[N][N][N][N][N];
 9 int n,m,p,x,sum[N][N];
10 
11 double Dfs(int a,int b,int c,int d,int k)
12 {
13     double &x=f[a][b][c][d][k];
14     if (x>=0) return x;
15     if (k==0)
16     {
17         x=sum[c][d]-sum[c][b-1]-sum[a-1][d]+sum[a-1][b-1];
18         return x=(x-ave)*(x-ave);
19     }
20     x=1e18;
21     for (int i=a+1; i<=c; ++i)
22         for (int j=0; j<k; ++j)
23             x=min(x,Dfs(a,b,i-1,d,j)+Dfs(i,b,c,d,k-j-1));
24     for (int i=b+1; i<=d; ++i)
25         for (int j=0; j<k; ++j)
26             x=min(x,Dfs(a,b,c,i-1,j)+Dfs(a,i,c,d,k-j-1));
27     return x;
28 }
29 
30 int main()
31 {
32     memset(f,-0x7f,sizeof(f));
33     cin>>n>>m>>p;
34     for (int i=1; i<=n; ++i)
35         for (int j=1; j<=m; ++j)
36         {
37             scanf("%d",&x);
38             sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+x;
39         }
40     ave=sum[n][m]*1.0/p;
41     Dfs(1,1,n,m,p-1);
42     printf("%.2lf",sqrt(f[1][1][n][m][p-1]/p));
43  } 
posted @ 2018-10-15 16:11  Refun  阅读(...)  评论(... 编辑 收藏