• 棋盘分割(二维区间DP)


    题目大意:给一个棋盘,棋盘上每个格子中都有一个值,现在需要将棋盘切成n个矩形,总共切n-1刀,求最小的均方差。均方差定义为:,其中

    题目分析:将均方差化简得到:均方差2=(Σxi2)/n-平均值2。显然,平均值2是定值,为数字总和除以n。只需让矩形的和的平方和最小即可。先预处理出数组s(x1,y1,x2,y2),表示左上角为(x1,y1),右下角为(x2,y2)的矩形上数字和的平方,定义dp(k,x1,y1,x2,y2)表示将矩形(x1,y1,x2,y2)切k刀能获得k+1个矩形时各矩形上数字和的最小平方和。则状态转移方程为:dp(k,x1,y1,x2,y2)=min{ min(dp(k-1,x1,y1,i,y2)+s(i+1,y1,x2,y2)),min(dp(k-1,i+1,y1,x2,y2)+s(x1,y1,i,y2))), x1≤i<x2 (横着切)

                 min(dp(k-1,x1,y1,x2,j)+s(x1,j+1,x2,y2)),min(dp(k-1,x1,j+1,x2,y2)+s(x1,y1,x2,j))), y1≤j<y2 (竖着切)

    }

    代码如下:

    # include<iostream>
    # include<cstring>
    # include<cstdio>
    # include<cmath>
    # include<algorithm>
    using namespace std;
    
    const int INF=1<<30;
    
    int w[8][8],n;
    int dp[16][8][8][8][8],s[8][8][8][8];
    
    int getS(int a,int b,int c,int d)
    {
        int sum=0;
        for(int i=a;i<=c;++i)
            for(int j=b;j<=d;++j)
                sum+=w[i][j];
        return sum*sum;
    }
    
    void work(int x,int y)
    {
        for(int i=x;i<8;++i)
            for(int j=y;j<8;++j)
                s[x][y][i][j]=getS(x,y,i,j);
    }
    
    void init()
    {
        for(int i=0;i<8;++i)
            for(int j=0;j<8;++j)
                work(i,j);
    }
    
    void ceShi()
    {
        for(int i=0;i<8;++i)
            for(int j=0;j<8;++j)
                for(int k=i;k<8;++k)
                    for(int l=j;l<8;++l)
                        cout<<i<<' '<<j<<' '<<k<<' '<<l<<' '<<s[i][j][k][l]<<endl;
    }
    
    int dfs(int k,int xa,int ya,int xb,int yb)
    {
        if(dp[k][xa][ya][xb][yb]>=0) return dp[k][xa][ya][xb][yb];
        int &u=dp[k][xa][ya][xb][yb];
        if(k==0) return u=s[xa][ya][xb][yb];
        if(xa==xb&&ya==yb) return u=s[xa][ya][xb][yb];
        u=INF;
        for(int i=xa;i<xb;++i){
            u=min(dfs(k-1,xa,ya,i,yb)+s[i+1][ya][xb][yb],u);
            u=min(dfs(k-1,i+1,ya,xb,yb)+s[xa][ya][i][yb],u);
        }
        for(int i=ya;i<yb;++i){
            u=min(dfs(k-1,xa,ya,xb,i)+s[xa][i+1][xb][yb],u);
            u=min(dfs(k-1,xa,i+1,xb,yb)+s[xa][ya][xb][i],u);
        }
        return u;
    }
    
    int main()
    {
        while(~scanf("%d",&n))
        {
            double sum=0.0;
            for(int i=0;i<8;++i)
                for(int j=0;j<8;++j){
                    scanf("%d",&w[i][j]);
                    sum+=(double)w[i][j];
                }
            sum/=(double)n;
            memset(s,0,sizeof(s));
            init();
            //ceShi();
            memset(dp,-1,sizeof(dp));
            dfs(n-1,0,0,7,7);
            double ans=(double)dp[n-1][0][0][7][7]/(double)n-sum*sum;
            printf("%.3lf
    ",sqrt(ans));
        }
        return 0;
    }
    

      

  • 相关阅读:
    有关于* daemon not running.starting it now on port 5037 *ADB
    在android中调用jni,出现ReferenceTable overflow (max=1024)
    15款优秀移动APP产品原型设计工具
    基于Jenkins+git+gradle的android持续集成,jenkinsgradle
    java代码分析及分析工具
    Android客户端SQLite数据库升级方案
    基于Android SQLite的升级
    Android唯一识别码
    Android中获取设备信息的方法
    Android Ubuntu 安装问题FAQ
  • 原文地址:https://www.cnblogs.com/20143605--pcx/p/5110132.html
Copyright © 2020-2023  润新知