您的位置:首页 > 其它

poj 1191 棋盘分割 DP

2011-08-25 16:35 441 查看
dp[k][x1][y1][x2][y2]表示(x1,y1)和(x2,y2)所围成的区域切割k次所得的方块各个平方的和

切割可以横向或纵向,切割一次之后可以在所得的两块中选择一块继续切割,另一块保持不动

s[x1][y1][x2][y2]表示(x1,y1)和(x2,y2)围成区域的平方和

dp[k][x1][y1][x2][y2] = min{

min(dp[k-1][x1][y1][x2][a] + s[x1][a+1][x2][y2],dp[k-1][x1][a+1][x2][y2] + s[x1][y1][x2][a]), 横向切割:选择上面的继续切割,选择下面的继续切割

min(dp[k-1][x1][y1][b][y2] + s[b+1][y1][x2][y2],dp[k-1][b+1][y1][x2][y2] + s[x1][y1][b][y2]) 纵向切割:选择左边的继续切割,选择右边的继续切割

}

#include<iostream>
#include<cmath>
using namespace std;
int dp[15][9][9][9][9],sum[9][9];
int SUM(int x1,int y1,int x2,int y2)
{
return sum[x2][y2] - sum[x1-1][y2] - sum[x2][y1-1] + sum[x1-1][y1-1];
}
int min(int a,int b)
{
return a < b ? a : b;
}
void solve(int k,int x1,int y1,int x2,int y2)
{
int a,t,MIN = 10000000;
if(dp[k][x1][y1][x2][y2] != -1) return ;
if(k == 0)
{
int t = SUM(x1,y1,x2,y2);
dp[k][x1][y1][x2][y2] = t*t;
return ;
}
for(a = x1;a < x2;a++)
{
solve(k-1,x1,y1,a,y2);
solve(k-1,a+1,y1,x2,y2);
int m = SUM(x1,y1,a,y2);
int n = SUM(a+1,y1,x2,y2);
t = min(dp[k-1][x1][y1][a][y2] + n*n,dp[k-1][a+1][y1][x2][y2] + m*m);
if(MIN > t)
MIN = t;
}
for(a = y1;a < y2;a++)
{
solve(k-1,x1,a+1,x2,y2);
solve(k-1,x1,y1,x2,a);
int m = SUM(x1,a+1,x2,y2);
int n = SUM(x1,y1,x2,a);
t = min(dp[k-1][x1][a+1][x2][y2] + n*n,dp[k-1][x1][y1][x2][a] + m*m);
if(MIN > t)
MIN = t;
}
dp[k][x1][y1][x2][y2] = MIN;
}
int main()
{
int n;
scanf("%d",&n);
int i,j,a,v;
double b;
for(i = 1;i <= 8;i++)
for(v = 0,j = 1;j <= 8;j++)
{
scanf("%d",&a);
v += a;
sum[i][j] = sum[i-1][j] + v;
}
memset(dp,-1,sizeof(dp));
solve(n-1,1,1,8,8);
v=sum[8][8]*sum[8][8];
int t = dp[n-1][1][1][8][8];
t*=n;t-=v;
b=double(t)/double(n*n); //要求精度的尽量把除法放在最后
printf("%.3lf\n",sqrt(b));
return 0;
}



                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: