ACM: 动态规划题 poj 1191 Nothing…

来源:互联网 发布:linux ed2k 终端 编辑:程序博客网 时间:2024/06/03 18:58
                                             棋盘分割

 

Description

将一个8*8的棋盘进行如下分割:将原棋盘割下一块矩形棋盘并使剩下部分也是矩形,再将剩下的部分继续如此分割,这样割了(n-1)次后,连同最后剩下的矩形棋盘共有n块矩形棋盘。(每次切割都只能沿着棋盘格子的边进行)
ACM: <wbr>动态规划题 <wbr>poj <wbr>1191 <wbr>Nothing <wbr>is <wbr>impossilbe

原棋盘上每一格有一个分值,一块矩形棋盘的总分为其所含各格分值之和。现在需要把棋盘按上述规则分割成n块矩形棋盘,并使各矩形棋盘总分的均方差最小。
均方差,其中平均值,xi为第i块矩形棋盘的总分。ACM: <wbr>动态规划题 <wbr>poj <wbr>1191 <wbr>Nothing <wbr>is <wbr>impossilbe


请编程对给出的棋盘及n,求出O'的最小值。

Input

第1行为一个整数n(1 < n< 15)。
第2行至第9行每行为8个小于100的非负整数,表示棋盘上相应格子的分值。每行相邻两数之间用一个空格分隔。

Output

仅一个数,为O'(四舍五入精确到小数点后三位)。

Sample Input

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

Sample Output

1.633

 
题意: 求方差最小.
解题思路: 黑书上的例题.
       1. 方差公式变形: 先取平方 δ^2 = (1/n)(∑Xi^2 + n*(x)^2 - 2 * x * ∑(Xi)^2) 
                                   = (1/n) * ∑(Xi)^2 - x^2     (x: 平均值).
       2. 公式变形后, 显然, 平均值是常量. 只要每个矩形的总分平均和最小即可.
       3. 要确定矩形, 左上角(x1,y1), 右下角(x2,y2)就可以确定出矩形.
          问题分析:
                (1). 设: s[x1][y1][x2][y2]表示矩阵的分数总和.
                dp[x1][y1][x2][y2][k]表示s[x1][y1][x2][y2]切割了k次后得到k+1块矩形的
                总分平方和和最小值.
          竖向: dp[x1][y1][x2][y2][k]=
                min( dp[x1][y1][a][y2][k-1] + s[a+1][y1][x2][y2]^2 ,
                     dp[a+1][y1][x2][y2][k-1] + s[x1][y1][a][y2]^2 );
          横向: dp[x1][y1][x2][y2][k]=
                min( dp[x1][y1][x2][a][k-1] + s[x1][a+1][x2][y2]^2 ,
                     dp[x1][a+1][x2][y2][k-1] + s[x1][y1][x2][a]^2 );
代码:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
using namespace std;
const int INF = (1<<30);
int dp[9][9][9][9][15];
int s[9][9][9][9];
int d[9][9];
int n;
inline int min(int a,int b)
{
 return a < b ? a : b;
}
void init()
{
 int x1, y1, x2, y2;
 int i, j;
 int sum;
 for(x1 = 1; x1 <= 8; ++x1)
 {
  for(y1 = 1; y1 <= 8; ++y1)
  {
   for(x2 = 1; x2 <= 8; ++x2)
   {
    for(y2 = 1; y2 <= 8; ++y2)
    {
     sum = 0;
     for(i = x1; i <= x2; ++i)
     {
      for(j = y1; j <= y2; ++j)
      {
       sum += d[i][j];
      }
     }
     s[x1][y1][x2][y2] = sum;
     dp[x1][y1][x2][y2][1] = sum*sum;
    }
   }
  }
 }
}
int main()
{
 int i, j;
// freopen("input.txt","r",stdin);
 while(scanf("%d",&n) != EOF)
 {
  memset(dp,0,sizeof(dp));
  memset(s,0,sizeof(s));
  memset(d,0,sizeof(d));
  double p = 0;
  int x1, y1, x2, y2;
  int a, t, temp;
  for(i = 1; i <= 8; ++i)
  {
   for(j = 1; j <= 8; ++j)
   {
    scanf("%d\n",&d[i][j]);
    p += d[i][j];
   }
  }
  p /= n;
  init();
  for(int k = 2; k <= n; ++k)
  {
   for(x1 = 1; x1 <= 8; ++x1)
   {
    for(y1 = 1; y1 <= 8; ++y1)
    {
     for(x2 = 1; x2 <= 8; ++x2)
     {
      for(y2 = 1; y2 <= 8; ++y2)
      {
       temp = INF;
       //横向
       for(a = x1; a < x2; ++a)
       {
        t = min( dp[x1][y1][a][y2][k-1] + s[a+1][y1][x2][y2]*s[a+1][y1][x2][y2],
           dp[a+1][y1][x2][y2][k-1] + s[x1][y1][a][y2]*s[x1][y1][a][y2] );
        if(temp > t)
         temp = t;
       }
       //竖向
       for(a = y1; a < y2; ++a)
       {
        t = min( dp[x1][y1][x2][a][k-1] + s[x1][a+1][x2][y2]*s[x1][a+1][x2][y2],
           dp[x1][a+1][x2][y2][k-1] + s[x1][y1][x2][a]*s[x1][y1][x2][a]);
        if(temp > t)
         temp = t;
       }
       dp[x1][y1][x2][y2][k] = temp;
      }
     }
    }
   }
  }
  printf("%.3f\n",sqrt( (double)dp[1][1][8][8][n] / (double)n - p*p) );
 }
 return 0;
}
0 0
原创粉丝点击