http://poj.org/problem?id=1191

(1)棋盘任意分割不是这道题所要讨论的,注意到题目中提到的“不允许的分割”,故会出现

          s=min(s, d(n-1, x1, y1, i, y2)+sum(i+1, y1, x2, y2));

          s=min(s, sum(x1, y1, i, y2)+d(n-1, i+1, y1, x2, y2));

   这样的规划关系(横向分割时)。

(2)比较两种写法:

       1)  float ans=d(k, 1, 1, 8, 8);
                  ans=sqrt((float)ans/k-pow(sqrt(sum(1,1,8,8))/k, 2.0));
                  printf("%.3f\n", ans);

       2)     float a, b,s;
                a=d(k,1,1,8,8), b=sqrt(sum(1,1,8,8))/k;
                s=sqrt(a/k-b*b);
                printf("%.3f\n", s);

   后者更优(0ms, 16ms), 且更不易出错。

(3)以(x1, y1, x2, y2)的形式描述矩形;

(4)将 data[i][j] 预处理成从左上角起的矩阵数字和,具体实现:

for(i=1;i<=8;i++)
            for(j=1;j<=8;j++)
            {
                scanf("%d", &data[i][j]);
                data[i][j]+=data[i-1][j]+data[i][j-1]-data[i-1][j-1];
            }

         

  调用所需矩阵的和值:

        s=data[x2][y2]-data[x1-1][y2]-data[x2][y1-1]+data[x1-1][y1-1];

(5)用到概率论的知识,只需使得最终各个小盘里数字和的平方和最小。

具体代码:

View Code
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<algorithm>
using namespace std;
int k, data[10][10];
int dp[16][10][10][10][10];
int sum(int x1, int y1, int x2, int y2)
{
    int s=data[x2][y2]-data[x1-1][y2]-data[x2][y1-1]+data[x1-1][y1-1];  //数学知识
    return s*s;
}
int d(int n, int x1, int y1, int x2, int y2)
{
    int i, j;
    if(dp[n][x1][y1][x2][y2]!=-1)
        return dp[n][x1][y1][x2][y2];
    if(n==1||x1==x2||y1==y2)   //不能再分割
    {
        dp[n][x1][y1][x2][y2]=sum(x1, y1, x2, y2);
        return dp[n][x1][y1][x2][y2];
    }
    int s=(1<<29);
    for(i=x1;i<x2;i++)   //横切
    {
        s=min(s, d(n-1, x1, y1, i, y2)+sum(i+1, y1, x2, y2));
        s=min(s, sum(x1, y1, i, y2)+d(n-1, i+1, y1, x2, y2));
    }
    for(j=y1;j<y2;j++)  //纵切
    {
        s=min(s, d(n-1, x1, y1, x2, j)+sum(x1, j+1, x2, y2));
        s=min(s, sum(x1, y1, x2, j)+d(n-1, x1, j+1, x2, y2));
    }
    dp[n][x1][y1][x2][y2]=s;
    return s;
}
int main()
{
    int i, j;
    while(scanf("%d", &k)!=EOF)
    {
        memset(data, 0, sizeof(data));
        for(i=1;i<=8;i++)
            for(j=1;j<=8;j++)
            {
                scanf("%d", &data[i][j]);
                data[i][j]+=data[i-1][j]+data[i][j-1]-data[i-1][j-1];  //预处理,注意data[i][j]含义
            }
        memset(dp, -1, sizeof(dp));
        float a, b,s;
        a=d(k,1,1,8,8), b=sqrt(sum(1,1,8,8))/k;
        s=sqrt(a/k-b*b);
        printf("%.3f\n", s);
    }
    return 0;
}