OpenJudge百炼-1191-棋盘分割-C语言-动态规划

来源:互联网 发布:斗鱼免费刷火箭软件 编辑:程序博客网 时间:2024/05/20 03:39

描述:
将一个8*8的棋盘进行如下分割:将原棋盘割下一块矩形棋盘并使剩下部分也是矩形,再将剩下的部分继续如此分割,这样割了(n-1)次后,连同最后剩下的矩形棋盘共有n块矩形棋盘。(每次切割都只能沿着棋盘格子的边进行)

原棋盘上每一格有一个分值,一块矩形棋盘的总分为其所含各格分值之和。现在需要把棋盘按上述规则分割成n块矩形棋盘,并使各矩形棋盘总分的均方差最小。
均方差,其中平均值,xi为第i块矩形棋盘的总分。
请编程对给出的棋盘及n,求出O'的最小值。
输入:
第1行为一个整数n(1 < n < 15)。
第2行至第9行每行为8个小于100的非负整数,表示棋盘上相应格子的分值。每行相邻两数之间用一个空格分隔。
输出:
仅一个数,为O'(四舍五入精确到小数点后三位)。
样例输入:
3
1 1 1 1 1 1 1 3
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 0
1 1 1 1 1 1 0 3
样例输出:
1.633

/*******************************************************文件名:百炼-1191**Copyright (c) 2015-2025 OrdinaryCrazy**创建人:OrdinaryCrazy**日期:20170817**描述:百炼1191参考答案**版本:1.0******************************************************/#include <stdio.h>#include <math.h>int min(int a,int b){    return a > b ? b : a;}/******************************************************这么复杂而没有头绪的题目,当然是要动态规划,首先,怎样模拟棋盘的分割就不是很好做,比较明智的做法就是记录我们现在需要分割的这块板子,是原来棋盘上的哪块区域,上顶y1,下底y2,左边x1,右边x2这样就得到了一组状态,还有一个问题,就是还要切几下这是5个状态,f(x1,x2,y1,y2,k)还有一个问题,这些状态对应的值是什么,直接对应方差好像有点说不通,因为这个值不能递归到子问题去做回到问题我们发现,平均值是整个棋盘的平均值,这个是很好算的,但是要算方差就比较费时了如果直接算的话,频繁的数组操作和复杂的计算必然会导致超时,需要再想办法首先化简一下表达式:@ = 根号(求和((xi - x)^2)/n)  = 根号(求和(xi^2 - 2*xi*x + x^2)/n)  = 根号((求和(xi^2) - 2*x*求和(xi))/n + x^2)  = 根号(求和(xi^2)/n - x^2)好了,我们只需要知道需要计算的所有板子的总分的平方就OK了然而这只是在计算上简单了一点点,数组操作还在,并没有本质上的提高下面想这样一个问题,如果我们知道点(1,1)和(x2,y2)形成的板子的总分那么减掉板(1,1)-(x2,y1-1),(1,1)-(x1-1,y2)再加上板(1,1)-(x1-1,y1-1)的总分就得到了板(x1,y1)-(x2,y2)总分。动态规划,动态规划.jpg*******************************************************/int n,board[9][9],sum[9][9],cost[9][9][9][9][15],inif = 1 << 30;/**cost[x1][y1][x2][y2][k]表示在板(x1,y1)-(x2,y2)上切k次的最小平方和我们最终的目标。就是使cost[1][1][8][8][n-1]达到最小值对于任意一块板子,就有状态递推方程:5种情况:这块板子切了不如不切,从左边切,从右边切,从上边切,从下边切,@为切割点cost[x1][y1][x2][y2][k] = min(cost[x1][y1][x2][y2][k],                              cost[x1][y1][@][y2][0] + cost[@+1][y1][x2][y2][k-1],                              cost[x1][y1][@][y2][k-1] + cost[@+1][y1][x2][y2][0],                              cost[x1][y1][x2][@][0] + cost[x1][@+1][x2][y2][k-1],                              cost[x1][y1][x2][@][k-1] + cost[x1][@+1][x2][y2][0])**/void count(int x1,int y1,int x2,int y2){    int a = sum[y2][x2] - sum[y1-1][x2] - sum[y2][x1-1] + sum[y1-1][x1-1];    cost[y1][x1][y2][x2][0] = a*a;}int main(){    int i,j,k,x1,x2,y1,y2;    scanf("%d",&n);    for(i = 1;i < 9;i++)        for(j = 1;j < 9;j++)            scanf("%d",&board[i][j]);    for(i = 1;i < 9;i++)        for(j = 1;j < 9;j++)        {            sum[i][j] = board[i][j] + sum[i - 1][j];            for(k = 1;k < j;k++)                sum[i][j] += board[i][k];        }    for(y1 = 1;y1 < 9;y1++)        for(x1 = 1;x1 < 9;x1++)            for(y2 = y1;y2 < 9;y2++)                for(x2 = x1;x2 < 9;x2++)                    count(x1,y1,x2,y2);    for(i = 1;i < n;i++)        for(y1 = 1;y1 < 9;y1++)            for(x1 = 1;x1 < 9;x1++)                for(y2 = y1;y2 < 9;y2++)                    for(x2 = x1;x2 < 9;x2++)                    {                        cost[y1][x1][y2][x2][i] = inif;                        for(k = x1;k < x2;k++)                            cost[y1][x1][y2][x2][i] = min(cost[y1][x1][y2][x2][i],min(cost[y1][x1][y2][k][0] + cost[y1][k+1][y2][x2][i-1],cost[y1][x1][y2][k][i-1] + cost[y1][k+1][y2][x2][0]));                        for(k = y1;k < y2;k++)                            cost[y1][x1][y2][x2][i] = min(cost[y1][x1][y2][x2][i],min(cost[y1][x1][k][x2][0] + cost[k+1][x1][y2][x2][i-1],cost[y1][x1][k][x2][i-1] + cost[k+1][x1][y2][x2][0]));                    }    printf("%.3f",sqrt((double)cost[1][1][8][8][n-1]/n - (double)(sum[8][8]*sum[8][8])/n/n));    return 0;}

原创粉丝点击