棋盘分割----POJ1191----DP

来源:互联网 发布:nodejs调用java接口 编辑:程序博客网 时间:2024/04/29 17:34

/*=========================================Author:Bob Lee2012.8.24=========================================核心思想:动态规划题目的大意是有一个8*8的矩阵,每一个都有一个非负整数然后要你切n-1下最后就有了n块,每块的和记为Xi然后给出一个公式Q=sqrt( sum(Xi-XAve)^2/n );要你求出Q的最小值首先是把Q平方,这样可以方便运算。得Q^2 = sum(Xi^2)/n - XAve^2XAve就是平均值,这个好求难点就在前面的那一个求和,这个我们得用DP求这是LRJ的黑书上关于动态规划的一道题目,核心思想已经讲了,我就原样COPYBy LRJ:dp[k][x1][y1][x2][y2]:左上角坐标为(x1,y1),右下角坐标为(x2,y2)的棋盘,设它把切割k次以后得到的k+1块矩形的总分平方和最小值.s[x1][y1][x2][y2]:左上角坐标为(x1,y1),右下角坐标为(x2,y2)的棋盘的总和的平方 dp[k][x1][y1][x2][y2] =1)按横的划分: min(dp[k-1][x1][y1][f][y2]+s[f+1][y1][x2][y2]    , dp[k-1][f+1][y1][x2][y2]+s[x1][y1][f][y2]);2)按竖的划分: min(dp[k-1][x1][y1][x2][f]+s[x1][f+1][x2][y2]    , dp[k-1][x1][f+1][x2][y2]+s[x1][y1][x2][f]);我把dp 换成了d这里还有一个地方就是处理s这个数组,这个还真的有点费脑筋(本人菜鸟)我就是用的一个count-map数组保存的由1,1到x,y的和,这样就可一通过double ans = count_map[i2][j2] - count_map[i2][j-1] - count_map[i-1][j2] + count_map[i-1][j-1];这个公式搞定来,自己可以演算一下还有一个精度问题,是用long double才AC的,用double就过不了,表示很纠结*/#include<iostream>#include<cmath>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>using namespace std;int n;long double d[16][9][9][9][9];long double s[9][9][9][9];double map[9][9];int count_map[9][9];long double sum;long double ave;const int m = 8;const double INF = 9999999999;double count(int i,int j,int i2,int j2){    double ans = count_map[i2][j2] - count_map[i2][j-1] - count_map[i-1][j2] + count_map[i-1][j-1];    return ans*ans;}void init()  //初始化s这个数组{    int i,j;    sum = 0;    memset(count_map,0,sizeof(count_map));    for(i=1;i<=8;i++)    {        for(j=1;j<=8;j++)        {            scanf("%lf",&map[i][j]);            sum+=map[i][j];            //count_map[i][j] 表示的是1,1到i,j的矩阵范围内的和            count_map[i][j] =   count_map[i][j-1]   +                                count_map[i-1][j]   -                                count_map[i-1][j-1] +                                map[i][j];        }    }    ave = sum*1.0/n;    int i2,j2;    for(i=1;i<=m;i++)    {        for(j=1;j<=m;j++)        {            for(i2=i;i2<=m;i2++)            {                for(j2 = j;j2<=m;j2++)                {                    s[i][j][i2][j2] = count(i,j,i2,j2);                    d[0][i][j][i2][j2] = s[i][j][i2][j2];                }            }        }    }}void dp(){    int k,i,j,i2,j2;    for(k=1;k<n;k++)    {        for(i=1;i<=m;i++)        {            for(j=1;j<=m;j++)            {                for(i2=i;i2<=m;i2++)                {                    for(j2 = j;j2<=m;j2++)                    {                        d[k][i][j][i2][j2] = INF;                        //首先是横着切                        int t;                        for( t = i;t<i2;t++)                            d[k][i][j][i2][j2] =    min(d[k][i][j][i2][j2],                                                        min(d[k-1][i][j][t][j2] + s[t+1][j][i2][j2],                                                            s[i][j][t][j2] + d[k-1][t+1][j][i2][j2]));                        //在就是竖着切                        for( t = j;t<j2;t++)                            d[k][i][j][i2][j2] =    min(d[k][i][j][i2][j2],                                                        min(d[k-1][i][j][i2][t] + s[i][t+1][i2][j2],                                                            s[i][j][i2][t] + d[k-1][i][t+1][i2][j2]));                    }                }            }        }    }}int main(){    while(scanf("%d",&n) != EOF)    {        init();        dp();        long double ans = d[n-1][1][1][m][m]*1.0/n - ave*ave;        printf("%.3f\n",(double)sqrt(ans));    }    return 0;}

题目地址:http://poj.org/problem?id=1191



原创粉丝点击