• NOI1999 棋盘分割


    题目:棋盘分割

    网址:https://www.luogu.com.cn/problem/P5752

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

    现在需要把棋盘按上述规则分割成n块矩形棋盘,并使各矩形棋盘总分的均方差最小。

    均方差image,其中平均值image,xi为第 i 块矩形棋盘的总分。

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

    输入格式

    第1行为一个整数n。

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

    输出格式

    输出最小均方差值(四舍五入精确到小数点后三位)。

    数据范围

    1<n<15

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

    这道题会发现最终影响结果大小只与分的块有关(分块哈哈);

    二维区间DP,最终注意以下细节即可:
    1.精度问题(如果代码过不去多半是这个问题);
    2.初始化(全部初始化为正无穷,不然还是容易错)。

    代码如下:

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    using namespace std;
    const int SIZE = 15 + 2;
    int n, s[SIZE][SIZE] = {};
    double ave = 0.000, dp[SIZE][SIZE][SIZE][SIZE][SIZE];
    double min(double x, double y)
    {
    	return x < y ? x : y;
    }
    double compute(int a1, int b1, int a2, int b2)
    {
    	double p = s[a2][b2] - s[a2][b1 - 1] - s[a1 - 1][b2] + s[a1 - 1][b1 - 1];
    	return (p - ave) * (p - ave)/ n;
    }
    int main()
    {
    	scanf("%d", &n);
    	for(int i = 1; i <= 8; ++ i)
    	{
    		for(int j = 1; j <= 8; ++ j)
    		{
    			scanf("%d", &s[i][j]);
    			s[i][j] += s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1];
    		}
    	}
    	ave = (double)s[8][8] / n;
    	for(int i = 1; i <= 8; ++ i)
    		for(int l = 1; l <= 8; ++ l)
    			for(int j = i; j <= 8; ++ j)
    				for(int r = l; r <= 8; ++ r)
    					dp[0][i][j][l][r] = compute(i, l, j, r);
    	for(int p = 1; p < n; ++ p)
    	{
    		for(int i = 1; i <= 8; ++ i)
    		{
    			for(int j = i; j <= 8; ++ j)
    			{
    				for(int l = 1; l <= 8; ++ l)
    				{
    					for(int r = l; r <= 8; ++ r)
    					{
    						double &ans = dp[p][i][j][l][r]; 
    						ans = 1e9;
    						for(int k = i; k < j; ++ k)
    						{
    							ans = min(ans, dp[0][k + 1][j][l][r] + dp[p - 1][i][k][l][r]);
    							ans = min(ans, dp[0][i][k][l][r] + dp[p - 1][k + 1][j][l][r]);
    						}
    						for(int k = l; k < r; ++ k)
    						{
    							ans = min(ans, dp[0][i][j][k + 1][r] + dp[p - 1][i][j][l][k]);
    							ans = min(ans, dp[0][i][j][l][k] + dp[p - 1][i][j][k + 1][r]);
    						}
    					}
    				}
    			}
    		}
    	}
    	printf("%.3lf
    ", (double)sqrt(dp[n - 1][1][8][1][8]));
    	return 0;
    }
    
  • 相关阅读:
    [置顶] Gridview中textbox列,按回车键或者上下键自动下移
    Java WebService入门实例
    hdu2553N皇后问题
    在SQL 脚本中进行 文件的读写
    按引用传递参数
    sencha 2.2详细说明
    [置顶] java高级工程师hibernate的知识重点
    [置顶] NYOJ117 求逆序数
    合作开发用到的几个 设计模式
    HDU1718:Rank
  • 原文地址:https://www.cnblogs.com/zach20040914/p/13172941.html
Copyright © 2020-2023  润新知