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
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 }