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

 

posted @ 2013-01-12 16:58  yefeng1627  阅读(250)  评论(0编辑  收藏  举报

Launch CodeCogs Equation Editor