poj 1191 棋盘分割

题目大意:

有一个8*8的正方形棋盘,每个格子有相对应的值,对于这个棋盘,我们可以割(n-1)次,使得切割后的n块棋盘权值和的标准差最小。

同时每次切割后下一次切割只能对上次被切割的其中一块进行切割,另一块就不能够再被切割了。

思路:

dp

首先可以注意到棋盘非常小,是8*8,n<15也并不大,先利用方差来计算,最后在用标准差

dp(x1,y1,x2,y2,k)表示(x1,y1) 为左上角(x2,y2)为右下角的矩形切k刀的答案。

首先,我们可以把方差的公式化简一下:
   1/n(x1^2+x2^2+...+xn^2-2*x1*avg-2*x2*avg-...-2*xn*avg+n*avg*avg)

=1/n(x1^2+x2^2+...+xn^2-2*avg*sum+sum*avg)

=1/n(x1^2+x2^2+...+xn^2-n*avg*avg)

=(x1^2+x2^2+...+xn^2)/n-avg^2

因为所有矩阵的和一定,所以我们先预处理出avg,然后dp表示每块的答案就好了

先预处理每块不切的情况 即dp(x1,y1,x2,y2,0)=sum^2

然后最外圈套k

枚举每一块的切割线以及左右两边哪边是新切的

最后把dp(0,0,7,7,n-1)带入公式

就做完了哈哈哈

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<cstdlib>
 6 #include<algorithm>
 7 #include<iomanip>
 8 #include<vector>
 9 #include<queue>
10 #define long long ll
11 #define inf 214748364
12 using namespace std;
13 int n,map[9][9],sum[9][9];
14 int f[9][9][9][9][17];
15 double avg;
16 int main()
17 {
18     scanf("%d",&n);
19     for(int i=0;i<8;i++)
20         for(int j=0;j<8;j++)
21         {
22             scanf("%d",&map[i][j]);
23             sum[i][j]=sum[i][j-1]+sum[i-1][j]-sum[i-1][j-1]+map[i][j];
24             avg+=map[i][j];
25         }
26     avg=1.0*avg/n;
27     for(int i1=0;i1<8;i1++)
28         for(int j1=0;j1<8;j1++)
29             for(int i2=i1;i2<8;i2++)
30                 for(int j2=j1;j2<8;j2++)
31                 {
32                     int s=sum[i2][j2]-sum[i1-1][j2]-sum[i2][j1-1]+sum[i1-1][j1-1];
33                     f[i1][j1][i2][j2][0]=s*s;
34                 }
35     for(int k=1;k<n;k++)
36         for(int i1=0;i1<8;i1++)
37             for(int j1=0;j1<8;j1++)
38                 for(int i2=i1;i2<8;i2++)
39                     for(int j2=j1;j2<8;j2++)
40                     {
41                         int d=1<<30;
42                         for(int o=i1;o<i2;o++) 
43                         {
44                             d=min(f[i1][j1][o][j2][0]+f[o+1][j1][i2][j2][k-1],d);
45                             d=min(f[i1][j1][o][j2][k-1]+f[o+1][j1][i2][j2][0],d);
46                         }
47                         for(int o=j1;o<j2;o++) 
48                         {
49                             d=min(f[i1][o+1][i2][j2][0]+f[i1][j1][i2][o][k-1],d);
50                             d=min(f[i1][o+1][i2][j2][k-1]+f[i1][j1][i2][o][0],d);
51                         }
52                         f[i1][j1][i2][j2][k]=d;
53                     }
54     double ans=f[0][0][7][7][n-1];
55     ans=sqrt(ans/n-avg*avg);
56     printf("%.3lf",ans);
57 }
View Code
原文地址:https://www.cnblogs.com/yyc-jack-0920/p/7217077.html