poj1191

均方差公式比较复杂,先将其变形

S^2 = 1/n∑(Xi - X)^2

   = 1/n(n*X^2 + ∑Xi^2 - 2*X∑Xi)

   = 1/n∑Xi^2 - X^2;   

   X表示均值

   由于均值是一定的(它等于方格里的数和除以n),所以只需要让每个矩形的总分的平方和尽量小

   对于左上角(x1,y1),右下角(x2,y2)的正方形,设它的总和为S[x1,y1,x2,y2]

   切割K次后得到的K+1块矩形的总分平方和最小值为dp[k,x1,y1,x2,y2]

   则它可以横着切,也可以竖着切,然后选一块切(这里用到了递归!)

   dp[k,x1,y1,x2,y2] =min{

      min{dp[k-1,x1,y1,a,y2]+S[a+1,y1,x2,y2] , dp[k-1,a+1,y1,x2,y2]+S[x1,y1,a,y2]}(x1<=a<x2),

      min{dp[k-1,x1,y1,x2,b]+S[x1,b+1,x2,y2] , dp[k-1,x1,b+1,x2,y2]+S[x1,y1,x2,b]}(y1<=b<y2)

   }

   设m为棋盘边长,则状态数目为m^4*n,决策数目为O(m)

   O(m^5*n))


一道比较高级的动态规划题目,真是有点困难,要注意,x,y,xx,yy所表达的意思,特别控制循环条件不能错(含右或含下线)


#include <iostream>
#include <string.h>
#include <vector>
#include <queue>
#include <stdio.h>
#include <cstdlib>
#include <math.h>
using namespace std;
int n;
int min(int a,int b)
{
    return a<b?a:b;
}
int sum[9][9][9][9],dp[16][9][9][9][9],gp[9][9];
void init()
{
    for(int x=0;x<8;x++)
        for(int y=0;y<8;y++)
            for(int xx=x;xx<8;xx++)
                for(int yy=y;yy<8;yy++)
                {
                    int ans=0;
                    for(int i=x;i<=xx;i++)
                        for(int j=y;j<=yy;j++)
                        {
                            ans+=gp[i][j];
                        }
                    sum[x][y][xx][yy]=ans*ans;
                    sum[xx][y][x][yy]=ans*ans;
                    sum[xx][yy][x][y]=ans*ans;
                    sum[x][yy][xx][y]=ans*ans;
                }
}
int DP(int k,int x,int y,int xx,int yy)
{
    if(k==n-1)
        return sum[x][y][xx][yy];
    if(dp[k][x][y][xx][yy]>=0)
        return dp[k][x][y][xx][yy];
    int ans=0;
    dp[k][x][y][xx][yy]=1<<29;
    for(int i=x;i<xx;i++)
    {
        ans=min(DP(k+1,x,y,i,yy)+sum[i+1][y][xx][yy],DP(k+1,i+1,y,xx,yy)+sum[x][y][i][yy]);
        dp[k][x][y][xx][yy]=min(ans,dp[k][x][y][xx][yy]);
    }
    for(int i=y;i<yy;i++)
    {
        ans=min(DP(k+1,x,y,xx,i)+sum[x][i+1][xx][yy],DP(k+1,x,i+1,xx,yy)+sum[x][y][xx][i]);
        dp[k][x][y][xx][yy]=min(ans,dp[k][x][y][xx][yy]);
    }
    return dp[k][x][y][xx][yy];
}
int main()
{
    int cnt=0;
    double ans;
    cin>>n;
    for(int i=0;i<8;i++)
    {
        for(int j=0;j<8;j++)
        {
            cin>>gp[i][j];
            cnt+=gp[i][j];
        }
    }
    init();
    memset(dp,-1,sizeof(dp));
    DP(0,0,0,7,7);
    ans=sqrt(dp[0][0][0][7][7]*1.0/n-((cnt*1.0)/n)*((cnt*1.0)/n));
    printf("%.3f\n",ans);
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值