zoukankan      html  css  js  c++  java
  • 棋盘切割 DP POJ 1191

    把方差公式先变形为 σ2 = (1/n)∑xi2-xa2

    xa为平均值。

    由于要求标准差最小,只需方差最小,平均值都是一样的,n也是一样的,这样原问题就变为求这n快小棋盘总分的平方和最小

    考虑左上角为(x1,y1),右上角为(x2,y2)的棋盘,设该棋盘切割K次后得到的K+1块矩形的总分平方和最小值为d[k,x1,y1,x2,y2]。该棋盘的总分平方和为

    s[x1,y1,x2,y2].则它可以沿着横线切,也可以沿着竖线切,然后选一块继续切(这里可以用递归完成)

    状态转移方程为d[k,x1,y1,x2,y2] =  min{

    min{ d[k-1,x1,y1,a,y2] + s[a+1,y1,x2,y2] , d[k-1,a+1,y1,x2,y2] + s[x1,y1,a,y2] },    (x1 <= a < x2)

    min{ d[k-1,x1,y1,x2,b] + s[x1,b+1,x2,y2] , d[k-1,x1,b+1,x2,y2] + s[x1,y1,x2,b] }  (y1 <= b < y2)

    }

    贴代码:

    View Code
     1 #include <cstdio>
     2 #include <cstring>
     3 #include <cmath>
     4 #define N 9
     5 #define min(a,b) a<b?a:b
     6 #define INF 100000000
     7 int n;
     8 int map[N][N];
     9 int presum[N][N];
    10 int d[16][N][N][N][N];//用d[k][x1][y1][x2][y2]表示左上角为(x1,y1)
    11 //右下角为(x2,y2)的棋盘切成了k+1块时最小的总分平方和值
    12 void presolve()
    13 {
    14     //预处理,算出所有左上角为(1,1)的所有矩阵元素和
    15     int i,j;
    16     for(i=0; i<=N; ++i)
    17         presum[0][i] = 0,presum[i][0] = 0;
    18     for(i=1; i<N; ++i)
    19     {
    20         int rowsum = 0;
    21         for(j=1; j<N; ++j)
    22         {
    23             scanf("%d",&map[i][j]);
    24             rowsum += map[i][j];
    25             presum[i][j] = presum[i-1][j] + rowsum;
    26         }
    27     }
    28 }
    29 int rectSquare(int x1,int y1,int x2,int y2)
    30 {
    31     //计算左上角为(x1,y1),右下角为(x2,y2)的棋盘的总分平方和
    32     int ret = presum[x2][y2] -presum[x1-1][y2] -presum[x2][y1-1] +presum[x1-1][y1-1];
    33     return ret*ret;
    34 }
    35 //DP程序
    36 int DP(int k,int x1,int y1,int x2,int y2)
    37 {
    38     int t,c,e;
    39     int MIN = INF;//用来求最后的d[k][x1][y1][x2][y2]
    40     if(d[k][x1][y1][x2][y2] != -1)//记忆化搜索???已经求过了,不再求,直接用
    41         return d[k][x1][y1][x2][y2];
    42     if(k == 0)//切0刀,不就是该棋盘了吗?最小值也是该棋盘的总分平方和,边界条件
    43         return d[k][x1][y1][x2][y2]=rectSquare(x1,y1,x2,y2);
    44     for(int a = x1; a < x2; ++a)
    45     {
    46         //横着切成了两块
    47         c = rectSquare(a+1,y1,x2,y2);
    48         e = rectSquare(x1,y1,a,y2);
    49         t = min(DP(k-1,x1,y1,a,y2) + c,DP(k-1,a+1,y1,x2,y2) + e);//选取一块继续切割
    50         MIN = min(MIN,t);
    51     }
    52     for(int b = y1; b < y2; ++b)
    53     {
    54         //竖着切成了两块
    55         c = rectSquare(x1,b+1,x2,y2);
    56         e = rectSquare(x1,y1,x2,b);
    57         t= min(DP(k-1,x1,y1,x2,b)+c,DP(k-1,x1,b+1,x2,y2)+e);//选取一块继续切割
    58         MIN = min(MIN,t);
    59     }
    60     d[k][x1][y1][x2][y2] = MIN;//所有的情况都考虑完后,所得就是该最小值
    61 //    printf("d[%d][%d][%d][%d][%d] = %d\n",k,x1,y1,x2,y2,d[k][x1][y1][x2][y2]);
    62     return MIN;
    63 }
    64 int main()
    65 {
    66 //    freopen("in.cpp","r",stdin);
    67     scanf("%d",&n);
    68     presolve();
    69     memset(d,-1,sizeof(d));
    70     int sumsquare = DP(n-1,1,1,8,8);
    71     double f = n*sumsquare - presum[8][8]*presum[8][8];
    72     f = sqrt(f)/n;
    73     printf("%.3f\n",f);
    74 //    printf("%d\n",0x7fffffff);
    75     return 0;
    76 }
    注意:
    用double,然后用%.3lf WA 用%.3fAC 在DP时min的初始值赋为10^7WA 赋为10^8AC 这点我还比较想得通,棋盘最大的总分和为6400,最大的平方和即为6400^6400,为40960000 你赋的min值至少应该大于这个数,否则就不对了,所以10^7可能会错 我中间赋过一个0x7fffffff,竟然导致出现了负数,怎么会啊。。。。。不了解
    补充:我现在理解了为什么出现负数,因为0x7fffffff是最大的整数数了,再加就溢出了,成为负的了·····
  • 相关阅读:
    vuejs中使用echart图表
    锚点链接
    如何动态修改网页的标题(title)?
    如何为图片添加热点链接?(map + area)
    cookie
    如何为你的网站添加标志性的图标(头像)呢?
    图片拖拽上传至服务器
    js定时器之setTimeout的使用
    input[type=file]中使用ajaxSubmit来图片上传
    input[type=file]样式更改以及图片上传预览
  • 原文地址:https://www.cnblogs.com/allh123/p/3061122.html
Copyright © 2011-2022 走看看