zoukankan      html  css  js  c++  java
  • BZOJ1048 [HAOI2007]分割矩阵

    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

    题解

    明明是标准差为什么要写方差!!!

    a,b,n都那么小,直接上$O(a^2b^2(a+b)n^2)$DP。。。

    因为方差等于平方的期望减期望的平方(期望在这里就是平均值),而后者是固定的(总和除以n),只需要求平方和最小即可。

    定义$f_{k,u,d,l,r}$为将上边界为u,下边界为d,左为l,右为r的矩阵切成k块后的平方和最小是多少,那么只需要枚举第一次从哪一行(或列)切和切成的两半各分多少份即可。

    状态$O(a^2b^2n)$个,转移$O(n(a+b))$。

    简单说,大概是$O(n^7)$的,如果a,b,n同阶的话。

    附代码:

    #include <algorithm>
    #include <cmath>
    #include <cstdio>
    using std::min;
    typedef double LL;
    const int N = 15;
    LL s[N][N], f[N][N][N][N][N];
    inline LL sqr(LL x) {
      return x * x;
    }
    inline LL sum(int l, int r, int u, int d) {
      return s[d][r] - s[d][l - 1] - s[u - 1][r] + s[u - 1][l - 1];
    }
    int main() {
      int a, b, n;
      scanf("%d%d%d", &a, &b, &n);
      for (int i = 1; i <= a; ++i)
        for (int j = 1; j <= b; ++j) {
          scanf("%lf", &s[i][j]);
          s[i][j] += s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1];
        }
      for (int u = 1; u <= a; ++u)
        for (int d = u; d <= a; ++d)
          for (int l = 1; l <= b; ++l)
            for (int r = l; r <= b; ++r)
              f[1][u][d][l][r] = sqr(sum(l, r, u, d));
      for (int k = 2; k <= n; ++k)
        for (int hei = 1; hei <= a; ++hei)
          for (int u = 1; u + hei - 1 <= a; ++u) {
            int d = u + hei - 1;
            for (int wid = 1; wid <= b; ++wid)
              for (int l = 1; l + wid - 1 <= b; ++l) {
                int r = l + wid - 1;
                LL &ans = f[k][u][d][l][r];
                ans = 1000000000000000000LL;
                for (int k1 = 1; k1 < k; ++k1) {
                  int k2 = k - k1;
                  for (int i = u + 1; i <= d; ++i)
                    ans = min(ans, f[k1][u][i - 1][l][r] + f[k2][i][d][l][r]);
                  for (int j = l + 1; j <= r; ++j)
                    ans = min(ans, f[k1][u][d][l][j - 1] + f[k2][u][d][j][r]);
                }
              }
          }
      printf("%.2lf
    ", sqrt(f[n][1][a][1][b] / n - sqr(s[a][b] / n)));
      return 0;
    }
    

      

  • 相关阅读:
    【MySQL】MySQL的Sequence
    【Spring】Junit加载Spring容器作单元测试
    【Java】JDBC连接MySQL
    【Java】斐波那契数列(Fibonacci Sequence、兔子数列)的3种计算方法(递归实现、递归值缓存实现、循环实现、尾递归实现)
    【Java】Map杂谈,hashcode()、equals()、HashMap、TreeMap、LinkedHashMap、ConcurrentHashMap
    【Java】常见的Set类型,HashSet、TreeSet、LinkedHashSet
    【数据结构和算法】选择排序
    【数据结构与算法】插入排序
    【数据结构与算法】冒泡排序
    【Web】写个HTML页面去调试HTTP接口方便些
  • 原文地址:https://www.cnblogs.com/y-clever/p/6994802.html
Copyright © 2011-2022 走看看