棋盘分割

#include <iostream>  
#include <cstdio>  
#include <cstring>  
#include <cmath>  
  
using namespace std;  
  
const double maxn=999999999;  
//说明下,本题中的矩形表示为用左上角的顶点坐标和右下角的顶点坐标确定一个矩形  
double sum[8][8][8][8];//dp[i][j][x][y]枚举记录每个矩形(i,j)(x,y)的和  
double dp[15][8][8][8][8];//dp[k][i][j][x][y]表示第k层矩形为(i,j)(x,y)的“矩形和值”的平方  
int map[8][8];  
double total;  
double average;  
  
double min(double a,double b){  
    return a<b?a:b;  
}  
  
int main()  
{  
    int n,i,j,k,x,y,mid;  
    total=0;  
    scanf("%d",&n);  

    for (i=0;i<8;++i)  
    {  
        for (j=0;j<8;++j)  
        {  
            scanf("%d",&map[i][j]);   //输入64个数,以空格分开
            total+=map[i][j];  
        }  
    } 
    
    average=total/(n*1.0);  //平均值

    for (i=0;i<8;i++)  
    {  
        for (j=0;j<8;j++)  
        {  
            for (x=i;x<8;x++)  
            {  
                total=0;  
                for (y=j;y<8;y++)//四重循环来求所有可能的矩形的块的分值  
                {  
                    total+=map[x][y];  
                    if (x==i)  
                    {  
                        sum[i][j][x][y]=total;  
                    }  
                    else  
                    {  
                        sum[i][j][x][y]=total+sum[i][j][x-1][y];  
                    }  
                }  
            }  
        }  
    }  

    for (i=0;i<8;i++)  
    {  
        for (j=0;j<8;j++)  
        {  
            for (x=i;x<8;x++)  
            {  
                for (y=j;y<8;y++)//此处四重循环就是将前面的和值转化为平方,然后赋值给DP数组  
                {  
                    //dp[0][i][j][x][y]=sum[i][j][x][y]*sum[i][j][x][y];
                    sum[i][j][x][y]*=sum[i][j][x][y];  
                    dp[0][i][j][x][y]=sum[i][j][x][y];  
                }  
            }  
        }  
    }  


    for (k=1;k<n;k++)  //k取1不取0是因为,比如n=3,但只切了两次
    {  
        for (i=0;i<8;i++)  
        {  
            for (j=0;j<8;j++)  
            {  
                for (x=i;x<8;x++)  
                {  
                    for (y=j;y<8;y++)  
                    {  
                        dp[k][i][j][x][y]=maxn;  //?????
                        double temp;  
                        for (mid=i;mid<x;mid++)//竖着枚举分割线  
                        {  
                            temp=min(dp[k-1][i][j][mid][y]+dp[0][mid+1][j][x][y],dp[k-1][mid+1][j][x][y]+dp[0][i][j][mid][y]); 
                            //
                            dp[k][i][j][x][y]=min(temp,dp[k][i][j][x][y]);  
                        }  
                        for(mid=j;mid<y;mid++){//横着枚举分割线  
                            temp=min(dp[k-1][i][j][x][mid]+dp[0][i][mid+1][x][y],dp[k-1][i][mid+1][x][y]+dp[0][i][j][x][mid]);  
                            //
                            dp[k][i][j][x][y]=min(temp,dp[k][i][j][x][y]);  
                        }//经过横着和竖着枚举分割线得出最优进行记录  
                    }  
                }  
            }  
        }  
    }  

    double ans=dp[n-1][0][0][7][7]/(n*1.0)-average*average;  
    //cout<<ans<<endl;  
    printf("%.3lf\n",sqrt(ans));//保留三位  
    return 0;  
}  
posted @ 2012-09-23 13:10  韩立  阅读(177)  评论(0)    收藏  举报