BZOJ 1048 分割矩阵

Description

将一个a*b的数字矩阵进行如下分割:将原矩阵沿某一条直线分割成两个矩阵,再将生成的两个矩阵继续如此分割(当然也可以只分割其中的一个),这样分割了(n-1)次后,原矩阵被分割成了n个矩阵。(每次分割都只能沿着数字间的缝隙进行)原矩阵中每一位置上有一个分值,一个矩阵的总分为其所含各位置上分值之和。现在需要把矩阵按上述规则分割成n个矩阵,并使各矩阵总分的均方差最小。请编程对给出的矩阵及n,求出均方差的最小值。

Input

第一行为3个整数,表示a,b,n≤10

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

HINT

 

Source

暴搜+记忆化。由于分割的块数一定,所以平均数可以直接计算出来。

f[i][j][k][l][p]表示横坐标为i到j,纵坐标为k到l的矩阵分成p份对答案贡献的最小值。(即为分割成的p份的每份的矩阵权值和与平均数的差的平方的和。eg:假设p=2,两个矩阵的权值和分别为s1、s2,平均数为m,则f[i][j][k][l][p]=(s1-m)2+(s2-m)2)。暴搜随便枚举几下就可以了。

最后求的是均方差,将方差开个根号即可。

 

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<cstdlib>
 5 #include<cmath>
 6 using namespace std;
 7 
 8 #define inf (1e18)
 9 #define maxn 15
10 int A,B,N; double f[maxn][maxn][maxn][maxn][maxn],s[maxn][maxn],ave;
11 
12 inline double qua(double a) { return a*a; }
13 
14 inline double calc(int h1,int h2,int l1,int l2)
15 {
16     double ret = 0;
17     for (int i = h1;i <= h2;++i)
18         for (int j = l1;j <= l2;++j) ret += s[i][j];
19     return ret;
20 }
21 
22 inline int size(int h1,int h2,int l1,int l2) { return (h2-h1+1)*(l2-l1+1); }
23 
24 inline double dfs(int h1,int h2,int l1,int l2,int k)
25 {
26     if (f[h1][h2][l1][l2][k] >= 0) return f[h1][h2][l1][l2][k];
27     if (k == 1) return f[h1][h2][l1][l2][k] = qua(calc(h1,h2,l1,l2)-ave);
28     f[h1][h2][l1][l2][k] = 1e18;
29     for (int i = 1;i < k;++i)
30     {
31         for (int j = h1;j < h2;++j)
32             if (size(h1,j,l1,l2)>=i&&size(j+1,h2,l1,l2)>=k-i)
33                 f[h1][h2][l1][l2][k] = min(f[h1][h2][l1][l2][k],dfs(h1,j,l1,l2,i)+dfs(j+1,h2,l1,l2,k-i));
34         for (int j = l1;j < l2;++j)
35             if (size(h1,h2,l1,j)>=i&&size(h1,h2,j+1,l2)>=k-i)
36                 f[h1][h2][l1][l2][k] = min(f[h1][h2][l1][l2][k],dfs(h1,h2,l1,j,i)+dfs(h1,h2,j+1,l2,k-i));
37     }
38     return f[h1][h2][l1][l2][k];
39 }
40 
41 int main()
42 {
43     scanf("%d %d %d",&A,&B,&N);
44     for (int i = 1;i <= A;++i)
45         for (int j = 1;j <= B;++j) scanf("%lf",s[i]+j);
46     memset(f,128,sizeof(f)); ave = calc(1,A,1,B)/(1.0*N);
47     dfs(1,A,1,B,N);
48     printf("%.2lf",sqrt(f[1][A][1][B][N]/(1.0*N)));    
49     return 0;
50 }
View Code

 

转载于:https://www.cnblogs.com/mmlz/p/4294089.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值