zoukankan      html  css  js  c++  java
  • poj 1191 棋盘分割 公式转换,横纵方向动态规划

      将方差公式转换 :

      方差:      均值:      

      得到:  

      我们知道 均值 X 为定值,与如何划分无关, 所以上述公式, 仅与    有关.

      那么我们可以通过求出最优的 , 即可求出最优 方差值.

      因为对于任意矩形,我们可以通过 其左上角,右下角 坐标来唯一确定,且要保证结果无后效性,我们增加一维切割次数N

      定义状态 DP(N,X1,Y1,X2,Y2) 为将 矩形(X1,Y1,X2,Y2)划分N次 的最小 平方值和

      则根据题目得到    

      对于当前状态 DP(K,X1,Y1,X2,Y2)

      对于 矩形 (X1,Y1,X2,Y2) ,依据题目要求只可在边缘切割,所以我们的切割方案分为两类:

        一,沿着 横坐标 切割,假定切割值为a,则划分为两个小矩形:S1(X1,Y1,A,Y2),S2(A+1,Y1,X2,Y2)        //这里是按点划分,而非按块,A点属于前者,则A+1属于后者

        二,沿着 纵坐标 切割,假定切割值为B,则划分为两个小矩形:S1(X1,Y1,X2,B),S2(X1,B+1,X2,Y2)

      两种情形下的划分后,我们可以从中任选一块继续划分

      所以状态转移方程为:

        DP(K,X1,Y1,X2,Y2)= MIN
        {    

            MIN( DP(K-1,X1,Y1,A,Y2)+S(A+1,Y1,X2,Y2), DP(K-1,A+1,Y1,X2,Y2)+S(X1,Y1,A,Y2) ),     // X1 <= A < X2

            MIN( DP(K-1,X1,Y1,X2,B)+S(X,B+1,X2,Y2),DP(K-1,X1,B+1,X2,Y2)+S(X1,Y1,X2,B))     // Y1 <= B < Y2

        }

      这里的 S(X1,Y1,X2,Y2)指此矩形的权值和的平方

      我们可以通过 O(N*N)预处理出 以(1,1)为左上角顶点的矩形权值和,然后通过简单容斥(S(X2,Y2)-S(X1-1,Y2)-S(X1,Y2-1)+S(X1-1,Y1-1) )

      来 O(1)实现策略。

      总时间复杂度为 O(M^5*N)

    解题代码:

    View Code
    #include<stdio.h>
    #include<string.h>
    #include<math.h>
    
    const int inf = 0x3fffffff;
    
    int MIN( int a, int b ){ return a < b ? a : b; }
    int mp[10][10], s[10][10], dp[15][10][10][10][10];
    int n;
    
    int comp( int x1, int y1, int x2, int y2 )
    {
        // return the area of (x1,y1,x2,y2)
        int tmp = s[x2][y2]-s[x2][y1-1]-s[x1-1][y2] + s[x1-1][y1-1];
        return (tmp*tmp);
    }
    
    int dfs( int k, int x1, int y1, int x2, int y2 )
    {
        if( dp[k][x1][y1][x2][y2] != -1 ) return dp[k][x1][y1][x2][y2];
        if( k == 0 ){
            int tmp = comp(x1,y1,x2,y2);
            return (dp[k][x1][y1][x2][y2]=tmp);
        } 
    
        int res = inf;
        // solve row
        for(int a = x1; a < x2; a++)
        {
            int tmp = MIN( dfs(k-1,x1,y1,a,y2)+comp(a+1,y1,x2,y2), dfs(k-1,a+1,y1,x2,y2)+comp(x1,y1,a,y2) );    
            res = MIN( res, tmp );    
        }
        // solve colomn
        for(int b = y1; b < y2; b++)
        {
            int tmp = MIN( dfs(k-1,x1,y1,x2,b)+comp(x1,b+1,x2,y2), dfs(k-1,x1,b+1,x2,y2)+comp(x1,y1,x2,b) );
            res = MIN( res, tmp );
        }
        return (dp[k][x1][y1][x2][y2]=res);
    }
    int main()
    {
    
        while( scanf("%d", &n) != EOF)
        {
            int sum = 0;    
            for(int i = 1; i <= 8; i++)
                for(int j = 1; j <= 8; j++)
                {
                    scanf("%d", &mp[i][j] );
                    sum += mp[i][j];
                }    
            memset(s,0,sizeof(s));    
            memset(dp,0xff,sizeof(dp));    
            // Get the Area S(1,1,x,y)     
            for(int r = 1; r <= 8; r++)
            {
                s[1][r] = s[1][r-1] + mp[1][r];
                s[r][1] = s[r-1][1] + mp[r][1];    
            }    
            for(int r = 2; r <= 8; r++)
                for(int c = 2; c <= 8; c++)
                    s[r][c] = s[r-1][c]+s[r][c-1]-s[r-1][c-1] + mp[r][c];    
    
            int x = dfs( n-1, 1, 1, 8, 8 );
    //        printf("x = %d\n", x );
            double ans =  sqrt( 1.*((x*n)-sum*sum)/(n*n) ) ;
            printf("%.3lf\n", ans );
        }
        return 0;
    }
  • 相关阅读:
    重温数据结构与算法(1) 构建自己的时间测试类
    读<<CLR via C#>>总结(11) 详谈事件
    读<<CLR via C#>>总结(13) 详谈泛型
    重温数据结构与算法(2) 编程中最常用,最通用的数据结构数组和ArrayList
    由String类的Split方法所遇到的两个问题
    读<<CLR via C#>>总结(6) 详谈实例构造器和类型构造器
    让我们都建立自己的知识树吧
    读<<CLR via C#>>总结(5) 如何合理使用类型的可见性和成员的可访问性来定义类
    读<<CLR via C#>>总结(10) 详谈委托
    读<<CLR via C#>>总结(4) 值类型的装箱和拆箱
  • 原文地址:https://www.cnblogs.com/yefeng1627/p/2857761.html
Copyright © 2011-2022 走看看