• NOI 193棋盘分割.cpp


    193:棋盘分割

    总时间限制: 
    1000ms
     
    内存限制: 
    65536kB
    描述
    将一个8*8的棋盘进行如下分割:将原棋盘割下一块矩形棋盘并使剩下部分也是矩形,再将剩下的部分继续如此分割,这样割了(n-1)次后,连同最后剩下的矩形棋盘共有n块矩形棋盘。(每次切割都只能沿着棋盘格子的边进行)

    原棋盘上每一格有一个分值,一块矩形棋盘的总分为其所含各格分值之和。现在需要把棋盘按上述规则分割成n块矩形棋盘,并使各矩形棋盘总分的均方差最小。
    均方差,其中平均值,xi为第i块矩形棋盘的总分。
    请编程对给出的棋盘及n,求出O'的最小值。
    输入
    第1行为一个整数n(1 < n < 15)。
    第2行至第9行每行为8个小于100的非负整数,表示棋盘上相应格子的分值。每行相邻两数之间用一个空格分隔。
    输出
    仅一个数,为O'(四舍五入精确到小数点后三位)。
    样例输入
    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 99
     1 /*
     2 z
     3 */
     4 #include<iostream>
     5 #include<cstdio>
     6 #include<cstring>
     7 #include<cmath>
     8 #define INF 0x3f3f3f3f
     9 using namespace std;
    10 int n;
    11 int s[9][9][9][9],c[9][9];
    12 int f[20][9][9][9][9];
    13 int add(int x1,int y1,int x2,int y2 )
    14 {
    15     int w=0;
    16     for(int i=x1;i<=x2;i++)
    17       for(int j=y1;j<=y2;j++)
    18           w+=c[i][j];
    19     return w;
    20 }
    21 int dfs(int k,int x1,int y1,int x2,int y2)
    22 {
    23     if(f[k][x1][y1][x2][y2]!=-1)
    24        return f[k][x1][y1][x2][y2];
    25     f[k][x1][y1][x2][y2]=INF;
    26     if(x1<x2)//横切
    27     {
    28         for(int x=x1; x<x2; x++)
    29         {
    30             int t1=dfs(k-1,x+1,y1,x2,y2);  //取上面那么递归计算下面
    31             int t2=dfs(k-1,x1,y1,x,y2);    //去下面那么递归计算上面
    32             int t=min(t1+s[x1][y1][x][y2],t2+s[x+1][y1][x2][y2]);
    33             f[k][x1][y1][x2][y2]=min(f[k][x1][y1][x2][y2],t);
    34         }
    35     }
    36         if(y1<y2)
    37         {
    38             for(int y=y1;y<y2;y++)
    39             {
    40                 int t1=dfs(k-1,x1,y+1,x2,y2) ;   //选左边那么递归计算右边
    41                 int t2=dfs(k-1,x1,y1,x2,y);     //选右边那么递归计算左边
    42                 int t=min(t1+s[x1][y1][x2][y],t2+s[x1][y+1][x2][y2]);
    43                 f[k][x1][y1][x2][y2]=min(f[k][x1][y1][x2][y2],t);
    44             }
    45         }
    46     return f[k][x1][y1][x2][y2];
    47 }
    48 int main()
    49 {
    50     int x1,y1,x2,y2,n;
    51     scanf("%d",&n);
    52     memset(f,-1,sizeof(f));
    53     for(int i=1;i<=8;i++)
    54       for(int j=1;j<=8;j++)
    55         scanf("%d",&c[i][j]);
    56     for(x1=1; x1<=8; x1++)
    57       for(x2=x1; x2<=8; x2++)
    58         for(y1=1; y1<=8; y1++)
    59           for(y2=y1; y2<=8; y2++)
    60           {
    61                int tmp=add(x1,y1,x2,y2);
    62                f[1][x1][y1][x2][y2]=s[x1][y1][x2][y2]=tmp*tmp;
    63           }
    64     dfs(n,1,1,8,8);
    65     double X,ans;
    66     X=1.*add(1,1,8,8);
    67     X=(X/n)*(X/n);
    68     //cout<<f[n][1][1][8][8]<<endl;
    69     ans=sqrt(1.0*f[n][1][1][8][8]/n-X);
    70     printf("%.3f
    ",ans);
    71     return 0;
    72 }
    #include <cstdio>
    #include <iostream>
    #include <cstring>
    #include <cmath>
    #define min(a,b) a<b?a:b
    #define INF 0x3f3f3f3f
    #define N 20
    using namespace std;
    int dp[N][10][10][10][10],s[10][10][10][10],c[10][10];
    int add(int x1,int y1,int x2,int y2)
    {
        int ans=0,x,y;
        for(x=x1; x<=x2; x++)
            for(y=y1; y<=y2; y++)
                ans+=c[x][y];
            coutMMans;
        return ans;
    }
    int dfs(int k,int x1,int y1,int x2,int y2)
    {
        if(dp[k][x1][y1][x2][y2]!=-1)
            return dp[k][x1][y1][x2][y2];
        int x,y,t1,t2,t;
        dp[k][x1][y1][x2][y2]=INF;
        if(x2>x1)  //至少有两行才能横着切
        {
            //1.选上面:dp[k][x1][y1][x2][y2]=s[x1][y1][x][y2]+dp[k-1][x+1][y1][x2][y2];
            //2.选下面:dp[k][x1][y1][x2][y2]=s[x+1][y1][x2][y2]+dp[k-1][x1][y1][x][y2];
            for(x=x1; x<x2; x++)
            {
                t1=dfs(k-1,x+1,y1,x2,y2);  //取上面那么递归计算下面
                t2=dfs(k-1,x1,y1,x,y2);    //去下面那么递归计算上面
                t=min(t1+s[x1][y1][x][y2] , t2+s[x+1][y1][x2][y2]);
                dp[k][x1][y1][x2][y2]=min(dp[k][x1][y1][x2][y2],t);
            }
        }
        if(y2>y1) //至少有两列才能竖着切
        {
            //1.选左边:dp[k][x1][y1][x2][y2]=s[x1][y1][x2][y]+dp[k-1][x1][y+1][x2][y2];
            //2.选右边:dp[k][x1][y1][x2][y2]=s[x1][y+1][x2][y2]+dp[k-1][x1][y1][x2][y];
    
            for(y=y1; y<y2; y++)
            {
                t1=dfs(k-1,x1,y+1,x2,y2); //选左边那么递归计算右边
                t2=dfs(k-1,x1,y1,x2,y);   //选右边那么递归计算左边
                t=min(t1+s[x1][y1][x2][y] , t2+s[x1][y+1][x2][y2]);
                dp[k][x1][y1][x2][y2]=min(dp[k][x1][y1][x2][y2],t);
            }
        }
    
        return dp[k][x1][y1][x2][y2];
    }
    int main()
    {
        int x1,x2,y1,y2,x,y,n;
        scanf("%d",&n);
        for(int i=1; i<=8; i++)
            for(int j=1; j<=8; j++)
                scanf("%d",&c[i][j]);
        memset(dp,-1,sizeof(dp));
        for(x1=1; x1<=8; x1++)
            for(x2=x1; x2<=8; x2++)
                for(y1=1; y1<=8; y1++)
                    for(y2=y1; y2<=8; y2++)
                    {
                        int tmp=add(x1,y1,x2,y2);
                        dp[1][x1][y1][x2][y2]=s[x1][y1][x2][y2]=tmp*tmp;
                    }
        dfs(n,1,1,8,8);
        double X,ans;
        X=1.*add(1,1,8,8);
        X=(X/n)*(X/n);
        cout<<X<<endl;
        ans=sqrt(1.0*dp[n][1][1][8][8]/n-X);
        printf("%.3f
    ",ans);
        return 0;
    }
    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.矩形区域,采用Excel的方法
    左上角(x1,y1):右下角(x2,y2)
    2.状态:
    f(i,x1,y1,x2,y2)表示
    把(x1,y1):(x2,y2)分割成i块的最小segma((x-x)^2)。
     
    对任意的矩形区域,i=1时的f值可以直接求得。
     
     
    3.状态转移:f(i,x1,y1,x2,y2)
    (1)枚举x1<=x<x2,横向分割成上下两个矩形
    (x1,y1):(x,y2) (x+1,y1):(x2,y2)
    把(x1,y1):(x,y2)分割成(i-1)矩形:f(i-1,x1,y1,x,y2)
    (x+1,y1):(x2,y2)作为1个矩形: f(1,x+1,y1,x2,y2)
    或者f(1,x1,y1,x,y2)+f(i-1,x+1,y1,x2,y2)
    (2)同理,枚举y1<=y<y2,纵向分割成左右两个矩形
    (x1,y1):(x2,y) (x1,y+1):(x2,y2)
    f(i-1,x1,y1,x2,y)+f(1,x1,y+1,x2,y2)
    f(1,x1,y1,x2,y)+f(i-1,x1,y+1,X2,Y2)
     
  • 相关阅读:
    字节顺序(大端小端)
    动态数组(一维二维)探秘
    算法十正则表达式匹配
    算法九回文数
    算法八字符串转换正数(atoi)
    windows server 2008配置多用户远程连接
    算法七整数反转
    原码反码补码
    算法六Z自形变换
    Java学习笔记之:Java Map集合
  • 原文地址:https://www.cnblogs.com/lutongxi/p/5370994.html
Copyright © 2020-2023  润新知