1191 棋盘分割

http://poj.org/problem?id=1191

 

 

刘汝佳黑书上有证明,先化简了求解公式,最后直接关联到xi2(i=1,2,3…,n)。

看了好久,起初被五维数组吓到了。

后来想了一下,记录主要是为了避免TLE而已。

递归的思想,n==2的情况来想,就容易很多了^ ^

附上书上的截图

//pku poj 1191 棋盘分割

#include<iostream>

#include<math.h>

double d[10][10][10][10][20]; //记录状态

double     s[10][10][10][10]; //记录每一块的和

double map[10][10];

double MY_min(double a,double b)  //比较函数

{

      return a<b ? a : b ;

}

double sum_area(int i1,int j1,int i2,int j2) //计算每一块的和

{

      if(s[i1][j1][i2][j2]>=0)      //这一步避免重复计算

            return s[i1][j1][i2][j2];

      int i,j;

      double sum=0;

      for(i=i1;i<=i2;i++)

      {

           for(j=j1;j<=j2;j++)

           {

                 sum+=map[i][j];

           }

      }

      s[i1][j1][i2][j2]=sum*sum; //预先平方

      return s[i1][j1][i2][j2];

}

double calculate(int i1,int j1,int i2,int j2,int n)

{

      if(d[i1][j1][i2][j2][n]>=0)

           return d[i1][j1][i2][j2][n];

      if(n==1)

           return s[i1][j1][i2][j2];

      double mini=99999999999;

      double temp_min;

      int i,j;

 

      //下面这两个循环判断横切还是竖切

      for(i=i1;i<i2;i++) //判断横切是取上半部分还是下半部分

      {

           temp_min=MY_min( calculate(i1,j1,i,j2,n-1)+sum_area(i+1,j1,i2,j2) ,  calculate(i+1,j1,i2,j2,n-1)+sum_area(i1,j1,i,j2)  );

           if(temp_min<mini)

                 mini=temp_min;

      }

      for(j=j1;j<j2;j++) //判断竖切是取左半部分还是右半部分

      {

           temp_min=MY_min( calculate(i1,j1,i2,j,n-1)+sum_area(i1,j+1,i2,j2) ,  calculate(i1,j+1,i2,j2,n-1)+sum_area(i1,j1,i2,j)  );

           if(temp_min<mini)

                 mini=temp_min;

      }

      d[i1][j1][i2][j2][n]=mini;//保存状态

      return d[i1][j1][i2][j2][n];

}

int main()

{

      int n;

      int i,j;

      double sum=0;

      double mini;

      scanf("%d",&n);

      for(i=1;i<=8;i++)

      {

           for(j=1;j<=8;j++)

           {

                 scanf("%lf",&map[i][j]);

                 sum+=map[i][j];

           }

      }

 

      //两个数组都先初始化为-1,方便之后每一次判断避免重复运算

      memset(d,-1,sizeof(d));

      memset(s,-1,sizeof(s));

 

      mini=calculate(1,1,8,8,n);

     

      sum/=(n*1.0);

      printf("%.3lf/n",sqrt(mini/(n*1.00)-(sum*sum)));

      return 0;

}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值