ACM PKU 1191 棋盘分割 http://acm.pku.edu.cn/JudgeOnline/problem?id=1191

     棋盘分割可以说是DP问题的经典,在刘汝佳老师的《算法艺术与信息学竞赛》上给出的一道例题,分析公式,要使最后的西格玛最小只要使每个方格的分数的平方和最小就行了,因为平均值使一个定值;

      思路:

1,先化简均方差公式,可以看出,只需要让每个分割后的矩形的总分的平方和尽量小,即可使均方差最小。
2,考虑左上角坐标为(x1,y1),右下角坐标为(x2,y2)的棋盘,设它的总和为value[x1,y1,x2,y2]切割k次以后得到k+1块矩形的总分平方和最小值为store[k,x1,y1,x2,y2],则它可以沿着横线切,也可以沿着竖线切,然后选一块继续切(递归)。。
3,由1,2部可以得到状态转移方程:
store[k,x1,y1,x2,y2]=min{
min{store[k-1,x1,y1,row,y2]+value[row+1,y1,x2,y2]^2,store[k-1,row+1,y1,x2,y2]+value[x1,y1,row,y2]^2},
min{store[k-1,x1,y1,x2,column]+value[x1,column+1,x2,y2]^2,store[k-1,x1,column+1,x2,y2]+value[x1,y1,x2,column]^2}}
其中:(x1<=row<x2),(y1<=column<y2);
初始值,对于k==0,store[k,x1,y1,x2,y2]=value[x1,y1,x2,y2]^2;
#include <iostream>
#include<iomanip>
#include<cmath>
using namespace std;

int n;
int sum[9][9];
const int Max = 9;
int store[15][9][9][9][9];


int min(int a,int b)
{ 
return a > b ? b:a;
}

int value(int x1,int y1,int x2,int y2)
{
return sum[x2][y2] - sum[x2][y1-1] - sum[x1-1][y2] + sum[x1-1][y1-1];
}

void input()
{
int i, j, part,wt;
    cin >> n;
for (i = 0;i < Max; i++)
{
   sum[0][i] = 0;
   sum[i][0] = 0;
}
for (i = 1;i < Max; i++)
   for (j = 1, part = 0;j < Max; j++)
   {
    cin >> wt;
    part += wt;
    sum[i][j] = sum[i-1][j] + part;
   }
}

int solve(int k,int x1,int y1,int x2,int y2)
{
int s0 ,s1, s ,row, column, mul;
int Min = 99999999;

if (k == 0 )
{
   s = value(x1,y1,x2,y2);
   store[k][x1][y1][x2][y2] = s*s;
   return s*s;
}

if (store[k][x1][y1][x2][y2] != -1)
   return store[k][x1][y1][x2][y2];

for (row = x1; row < x2; row++)
{
   s0 = value(x1, y1, row, y2);
   s1 = value(row+1, y1, x2, y2);
   mul = min(solve(k-1,x1,y1,row,y2)+ s1*s1 ,solve(k-1,row+1,y1,x2,y2) + s0*s0);
    if (mul < Min)
     Min = mul;
}

for (column= y1;column < y2; column++)
{
   s0 = value(x1, y1, x2, column);
   s1 = value(x1, column+1, x2, y2);
   mul = min((solve(k-1,x1, y1, x2, column) + s1*s1),(solve(k-1,x1,column+1, x2, y2) + s0*s0));
    if (mul < Min)
     Min = mul;
}
    store[k][x1][y1][x2][y2] = Min;
    return Min;
}

int main ()
{
    input();

memset(store,-1,sizeof(store));

int temp = solve(n-1,1,1,8,8);

int total = sum[8][8] * sum[8][8];

temp =temp*n - total;

double p = sqrt((temp*1.0)/(n*n*1.0));

cout<<setiosflags(ios::fixed)<<setprecision(3)<<p<<endl;

return 0;
}

posted on 2011-05-06 18:46  _Clarence  阅读(197)  评论(0编辑  收藏  举报

导航