[NOI99]棋盘分割(Chessboard Division)

棋盘分割(NOI99)
Chessboard Division
Chess.{pas|bas|c}
Chess.exe

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

原棋盘上每一格有一个分值,一块矩形棋盘的总分为其所含各格分值之和。现在需要把棋盘按上述规则分割成n块矩形棋盘,并使各矩形棋盘总分的均方差最小。

请编程对给出的棋盘及n,求出均方差σ的最小值。

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

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

样例输入
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

题解

现在NOI的题做起来还是很费事……那个sigma的式子的化简则完全是参照lrj的牛书完成的,好失败……

中间调试了相当一段时间,都是由于些弱智错误……囧

#include <fstream>
#include <cassert>
#include <cmath>
#include <iomanip>
using namespace std;
ifstream fin("chess.in");
ofstream fout("chess.out");
int N;

unsigned score[8][8][8][8];
bool scored[8][8][8][8];
unsigned get_score(int x1, int y1, int x2, int y2)
{
   assert(x1<=x2&&y1<=y2);
   if(scored[x1][y1][x2][y2])   return score[x1][y1][x2][y2];
   scored[x1][y1][x2][y2]=true;
   unsigned sum=0;
   for(int x=x1;x<=x2;x++)
      for(int y=y1;y<=y2;y++)
         sum+=score[x][y][x][y];
   score[x1][y1][x2][y2]=sum;
   return sum;
}

unsigned dp[8][8][8][8][15];
bool checked[8][8][8][8][15];
unsigned memo(int x1, int y1, int x2, int y2, int n)
{
   assert(x1<=x2&&y1<=y2);
   if(checked[x1][y1][x2][y2][n])
      return dp[x1][y1][x2][y2][n];
   checked[x1][y1][x2][y2][n]=true;
   if(n==1)
   {
      dp[x1][y1][x2][y2][n]
                =get_score(x1,y1,x2,y2)*get_score(x1,y1,x2,y2);
      return dp[x1][y1][x2][y2][n];
   }

   unsigned ans=INT_MAX;
   for(int x=x1,m;x<x2;x++)
   {
      m=memo(x+1,y1,x2,y2,n-1);
      if(m<INT_MAX)
         ans=min(ans,get_score(x1,y1,x,y2)*get_score(x1,y1,x,y2)
            +memo(x+1,y1,x2,y2,n-1));
      m=memo(x1,y1,x,y2,n-1);
      if(m<INT_MAX)
         ans=min(ans,memo(x1,y1,x,y2,n-1)
            +get_score(x+1,y1,x2,y2)*get_score(x+1,y1,x2,y2));
   }
   for(int y=y1,m;y<y2;y++)
   {
      m=memo(x1,y+1,x2,y2,n-1);
      if(m<UINT_MAX)
         ans=min(ans,get_score(x1,y1,x2,y)*get_score(x1,y1,x2,y)
            +memo(x1,y+1,x2,y2,n-1));
      m=memo(x1,y1,x2,y,n-1);
      if(m<UINT_MAX)
         ans=min(ans,memo(x1,y1,x2,y,n-1)
            +get_score(x1,y+1,x2,y2)*get_score(x1,y+1,x2,y2));
   }
   dp[x1][y1][x2][y2][n]=ans;
   return ans;
}

int main()
{
   fin >> N;
   for(int y=0;y<=7;y++)
      for(int x=0;x<=7;x++)
      {
         fin >> score[x][y][x][y];
         scored[x][y][x][y]=true;
      }
   double x_=double(get_score(0,0,7,7))/N;
   fout << fixed << setprecision(3)
      << sqrt(double(memo(0,0,7,7,N))/N-x_*x_) << endl;
   return 0;
}

可能你对下面的文章也感兴趣:

    分享到:

标签云