棋盘分割--POJ 1191

1、题目类型:DP、概率论。

2、解题思路:DP递推式(以上下切为例):

    for i=x1...x2

       Sum[k][x1][y1][x2][y2]=Min{Sum[k][x1][y1][x2][y2],
              Min{DP(k-1,x1,y1,i,y2)+Bak[i+1][y1][x2][y2],DP(k-1,i+1,y1,x2,y2)+Bak[x1][y1][i][y2]}}; 

     其中 i 表示切割位置,k 表示切割次数。

3、注意事项:递归循环的调用。

4、参考博客:http://www.cnblogs.com/cnjy/articles/1549241.html

5、实现方法:

#include<iostream>
#include
<cmath>
using namespace std;

const int INF=0xffffff;
int Map[9][9],Bak[9][9][9][9];
double Sum[16][9][9][9][9];

//返回区域的和的平方
int GetSum(int x1,int y1,int x2,int y2)
{
int i,j,ret=0;
for(i=x1;i<=x2;++i)
for(j=y1;j<=y2;++j)
ret
+=Map[i][j];
return ret*ret;
}

//记录任何矩形区域的和的平方
void Init()
{
int i,j,k,l;
for(i=1;i<=8;++i)
for(j=1;j<=8;++j)
for(k=i;k<=8;++k)
for(l=j;l<=8;++l)
Bak[i][j][k][l]
=GetSum(i,j,k,l);

}

double GetMin(double x,double y)
{
return x<y?x:y;
}

double DP(int k,int x1,int y1,int x2,int y2)
{
int i,j;
if(Sum[k][x1][y1][x2][y2]>=0)
return Sum[k][x1][y1][x2][y2];
if(k==1)
return Bak[x1][y1][x2][y2];
Sum[k][x1][y1][x2][y2]
=INF;
//进行上下切
for(i=x1;i<x2;++i)
{
Sum[k][x1][y1][x2][y2]
=GetMin(Sum[k][x1][y1][x2][y2],
GetMin(DP(k
-1,x1,y1,i,y2)+Bak[i+1][y1][x2][y2],DP(k-1,i+1,y1,x2,y2)+Bak[x1][y1][i][y2]));
}
//进行左右切
for( j=y1; j<y2; ++j )
{
Sum[k][x1][y1][x2][y2]
=GetMin( Sum[k][x1][y1][x2][y2],
GetMin(DP(k
-1,x1,y1,x2,j)+Bak[x1][j+1][x2][y2],DP(k-1,x1,j+1,x2,y2)+Bak[x1][y1][x2][j])) ;
}
return Sum[k][x1][y1][x2][y2];
}

int main()
{
int i,j,n;
double ans,all=0;
cin
>>n;
for(i=1;i<9;++i)
{
for(j=1;j<9;++j)
{
cin
>>Map[i][j];
all
+=Map[i][j];
}
}
Init();
memset(Sum,
-1,sizeof(Sum));
all
/=n;
DP(n,
1,1,8,8);
ans
=sqrt(Sum[n][1][1][8][8]/n-all*all);
printf(
"%.3f\n",ans);
return 1;
}

 

 

 

posted @ 2010-08-06 19:25  勇泽  阅读(503)  评论(0编辑  收藏  举报