题目:POJ1911.
题目大意:给定一个
8
∗
8
8*8
8∗8的矩阵,要求将它切割
n
n
n次(每一次次切割后要选择一个部分,以后只能在这个部分切割),使得它们的均方差最小.设
x
i
x_i
xi为第
i
i
i个子矩阵的权值和,那么它们的均方差
σ
\sigma
σ定义为:
x
ˉ
=
∑
i
=
1
n
x
i
n
,
σ
=
∑
i
=
1
n
(
x
i
−
x
ˉ
)
2
n
\bar{x}=\frac{\sum_{i=1}^{n}x_i}{n},\sigma=\sqrt{\frac{\sum_{i=1}^{n}(x_i-\bar{x})^2}{n}}
xˉ=n∑i=1nxi,σ=n∑i=1n(xi−xˉ)2
WA这怎么必须选定一部分继续切啊…
首先我们发现这个均方差的公式很棘手,想想如何改一改均方差的公式:
σ
=
∑
i
=
1
n
(
x
i
−
x
ˉ
)
2
n
=
∑
i
=
1
n
x
i
2
−
2
x
i
x
ˉ
+
x
ˉ
2
n
=
∑
i
=
1
n
x
i
2
n
−
2
x
ˉ
∑
i
=
1
n
x
i
n
+
x
ˉ
2
=
∑
i
=
1
n
x
i
2
n
−
2
x
ˉ
2
+
x
ˉ
2
=
∑
i
=
1
n
x
i
2
n
−
x
ˉ
2
\sigma=\sqrt{\frac{\sum_{i=1}^{n}(x_i-\bar{x})^2}{n}}\\ =\sqrt{\frac{\sum_{i=1}^{n}x_i^2-2x_i\bar{x}+\bar{x}^2}{n}}\\ =\sqrt{\frac{\sum_{i=1}^{n}x_i^2}{n}-2\bar{x}\frac{\sum_{i=1}^{n}x_i}{n}+\bar{x}^2}\\ =\sqrt{\frac{\sum_{i=1}^{n}x_i^2}{n}-2\bar{x}^2+\bar{x}^2}\\ =\sqrt{\frac{\sum_{i=1}^{n}x_i^2}{n}-\bar{x}^2}\\
σ=n∑i=1n(xi−xˉ)2=n∑i=1nxi2−2xixˉ+xˉ2=n∑i=1nxi2−2xˉn∑i=1nxi+xˉ2=n∑i=1nxi2−2xˉ2+xˉ2=n∑i=1nxi2−xˉ2
容易发现 x ˉ \bar{x} xˉ是个定值(整个矩阵的和除以 n n n),所以我们只需要让 ∑ i = 1 n x i 2 \sum_{i=1}^{n}x_i^2 ∑i=1nxi2最小即可.
这还不简单?设
f
[
i
]
[
i
0
]
[
j
0
]
[
i
1
]
[
j
1
]
f[i][i0][j0][i1][j1]
f[i][i0][j0][i1][j1]表示左上角为
(
i
0
,
j
0
)
(i0,j0)
(i0,j0)右下角为
(
i
1
,
j
1
)
(i1,j1)
(i1,j1)被分割
i
i
i次的最小值即可.转移如下:
f
[
i
]
[
i
0
]
[
j
0
]
[
i
1
]
[
j
1
]
=
min
k
=
1
i
−
1
{
min
t
=
i
0
i
1
−
1
{
f
[
k
]
[
i
0
]
[
j
0
]
[
t
]
[
j
1
]
+
f
[
i
−
k
]
[
t
+
1
]
[
j
0
]
[
i
1
]
[
j
1
]
}
,
min
t
=
j
0
j
1
−
1
{
f
[
k
]
[
i
0
]
[
j
0
]
[
i
1
]
[
t
]
+
f
[
i
−
k
]
[
i
0
]
[
t
+
1
]
[
i
1
]
[
j
1
]
}
}
f[i][i0][j0][i1][j1]=\min_{k=1}^{i-1}\{ \min_{t=i0}^{i1-1} \{ f[k][i0][j0][t][j1]+f[i-k][t+1][j0][i1][j1] \},\\\min_{t=j0}^{j1-1} \{ f[k][i0][j0][i1][t]+f[i-k][i0][t+1][i1][j1] \} \}
f[i][i0][j0][i1][j1]=k=1mini−1{t=i0mini1−1{f[k][i0][j0][t][j1]+f[i−k][t+1][j0][i1][j1]},t=j0minj1−1{f[k][i0][j0][i1][t]+f[i−k][i0][t+1][i1][j1]}}
时间复杂度 O ( 8 5 n ) O(8^5n) O(85n).
代码如下:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=15,M=8,INF=(1<<30)-1;
int n,a[M+9][M+9],dp[N+9][M+9][M+9][M+9][M+9],sum;
Abigail into(){
scanf("%d",&n);
for (int i=1;i<=M;++i)
for (int j=1;j<=M;++j){
scanf("%d",&a[i][j]);
sum+=a[i][j];
}
}
Abigail work(){
for (int i0=1;i0<=M;++i0)
for (int i1=i0;i1<=M;++i1)
for (int j0=1;j0<=M;++j0)
for (int j1=j0;j1<=M;++j1){
int &t=dp[1][i0][j0][i1][j1];
for (int i=i0;i<=i1;++i)
for (int j=j0;j<=j1;++j)
t+=a[i][j];
t=t*t;
}
for (int i=2;i<=n;++i)
for (int leni=1;leni<=M;++leni)
for (int i0=1;i0+leni-1<=M;++i0){
int i1=i0+leni-1;
for (int lenj=1;lenj<=M;++lenj)
for (int j0=1;j0+lenj-1<=M;++j0){
int j1=j0+lenj-1,&t=dp[i][i0][j0][i1][j1];
t=INF;
for (int midi=i0;midi<i1;++midi)
t=min(t,min(dp[i-1][i0][j0][midi][j1]+dp[1][midi+1][j0][i1][j1],
dp[1][i0][j0][midi][j1]+dp[i-1][midi+1][j0][i1][j1]));
for (int midj=j0;midj<j1;++midj)
t=min(t,min(dp[i-1][i0][j0][i1][midj]+dp[1][i0][midj+1][i1][j1],
dp[1][i0][j0][i1][midj]+dp[i-1][i0][midj+1][i1][j1]));
}
}
}
Abigail outo(){
printf("%.3lf\n",sqrt(1.0*dp[n][1][1][M][M]/n-1.0*sum*sum/n/n));
}
int main(){
into();
work();
outo();
return 0;
}