棋盘(知道了为什么可以用区间dp)

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

现在需要把棋盘按上述规则分割成n块矩形棋盘,并使各矩形棋盘总分的均方差最小。
在这里插入图片描述
请编程对给出的棋盘及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

这道题目是来自1999 年的NOI,虽然是NOI, 但是由于年份久远,是可以做的(02 说要克服心里的恐惧)。

思路:首先这道题目的大体做法要搞清楚,刚看到这道题目,虽然是区间dp专题,但是也搞不懂该怎么做。

其实我写下来的目的是想搞明白这道题目为什么可以用区间dp来做,区间dp的限制是什么?
其实我想的是, 首先能不能用区间dp的主要的因素是分成的两个区间与主区间存不存在一定的联系, 区间分成的两部分之间的关系和融合为一起的区间的联系或者是加在一起, 或者是乘在一起, 就像本题目一样, 两个分成的区间的最小方差加在一起难道就是总区间的最小值了吗,当然在知道题解后, 答案是肯定的, 但是为什么呢, 我们总要问一下, 这样我们才能进步, 可能从这道题目的收获最大并不是知道这道题目怎么做, 而是这道题目启发了你什么, 要怎么样的总结,那么回归正题, 这道题目为什么可以这样做呢。

v

推导了一下, 发现只要满足切割成的部分, 那么这样就能很好的解释了为什么两个分区间的最大值的和等于总区间的最大值了, 并且满足相加性。

对应着代码有两种方式, 一个是记忆化搜索, 这个是推荐的解法, 另一种是直接暴力循环, 这样也可以, 思维会稍微难点(也没难多少啦)。

有点长, 复习的话大概看看就好了

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>

using namespace std;

const int N = 9, M = 16, INF = 0x3f3f3f3f;

int s[N][N], a[N][N];

int f[M][N][N][N][N];

int get(int x1, int y1, int x2, int y2)
{
    int t = s[x2][y2] - s[x2][y1 - 1] - s[x1 - 1][y2] + s[x1 - 1][y1 - 1];
    return t * t;
}

int dfs(int x1, int y1, int x2, int y2, int k)
{
    int &v = f[k][x1][y1][x2][y2];
    if(v != -1) return v;
    if(k == 0) return v = get(x1, y1, x2, y2);
    
    v = INF;
    for(int i = x1; i < x2; i ++)
    {
        v = min(v, dfs(x1, y1, i, y2, k - 1) + f[0][i + 1][y1][x2][y2]);
        v = min(v, dfs(i + 1, y1, x2, y2, k - 1) + f[0][x1][y1][i][y2]);
        //min(f[k - 1][x1][y1][i][y2] + f[0][i + 1][y1][x2][y2], f[k - 1][i + 1][y1][x2][y2] + f[0][x1][y1][i][y2])
    }
    for(int i = y1; i < y2; i ++)
    {
        v = min(v, dfs(x1, y1, x2, i, k - 1) + f[0][x1][i + 1][x2][y2]);
        v = min(v, dfs(x1, i + 1, x2, y2, k - 1) + f[0][x1][y1][x2][i]);
       // min(f[k - 1][x1][y1][x2][i] + f[0][x1][i + 1][x2][y2],  + f[k - 1][x1][i + 1][x2][y2])
    }
    
    return v;
}


int main()
{
    int n; cin >> n;
    
    for(int i = 1; i <= 8; i ++)
        for(int j = 1; j <= 8; j ++)
        {
            cin >> a[i][j];
            s[i][j] = s[i - 1][j] +  s[i][j - 1] - s[i - 1][j - 1] + a[i][j];
        }
    memset(f, -1, sizeof f);
    for(int x1 = 1; x1 <= 8; x1 ++)
        for(int y1 = 1; y1 <= 8; y1 ++)
            for(int x2 = x1; x2 <= 8; x2 ++)
                for(int y2 = y1; y2 <= 8; y2 ++)
                {
                    int t = get(x1, y1, x2, y2);
                    f[0][x1][y1][x2][y2] = t;
                }
    
    dfs(1, 1, 8, 8, n - 1);
    
    double ave = (double)s[8][8] / n;
    
    double ans = sqrt(((double)f[n - 1][1][1][8][8] / n - ave * ave));
    
    printf("%.3lf", ans);
    
    return 0;
}

还有短的!!

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>

using namespace std;

const int N = 9, M = 16, INF = 0x3f3f3f3f;

int s[N][N], a[N][N];

int f[M][N][N][N][N];

int get(int x1, int y1, int x2, int y2)
{
    return s[x2][y2] - s[x2][y1 - 1] - s[x1 - 1][y2] + s[x1 - 1][y1 - 1];
    
    
}
int main()
{
    int n; cin >> n;
    
    for(int i = 1; i <= 8; i ++)
        for(int j = 1; j <= 8; j ++)
        {
            cin >> a[i][j];
            s[i][j] = s[i - 1][j] +  s[i][j - 1] - s[i - 1][j - 1] + a[i][j];
        }
    
    for(int x1 = 1; x1 <= 8; x1 ++)
        for(int y1 = 1; y1 <= 8; y1 ++)
            for(int x2 = x1; x2 <= 8; x2 ++)
                for(int y2 = y1; y2 <= 8; y2 ++)
                {
                    int t = get(x1, y1, x2, y2);
                    f[0][x1][y1][x2][y2] = t * t;
                }

    for(int k = 1; k < n; k ++)
        for(int x1 = 1; x1 <= 8; x1 ++)
            for(int y1 = 1; y1 <= 8; y1 ++)
                for(int x2 = x1; x2 <= 8; x2 ++)
                    for(int y2 = y1; y2 <= 8; y2 ++)
                    {
                        int minv = INF;
                        for(int i = x1; i < x2; i ++)
                        {
                            minv = min(minv, min(f[k - 1][x1][y1][i][y2] + f[0][i + 1][y1][x2][y2], f[k - 1][i + 1][y1][x2][y2] + f[0][x1][y1][i][y2]));
                        }
                        
                        for(int i = y1; i < y2; i ++)
                        {
                            minv = min(minv, min(f[k - 1][x1][y1][x2][i] + f[0][x1][i + 1][x2][y2], f[0][x1][y1][x2][i] + f[k - 1][x1][i + 1][x2][y2]));
                        }
                        f[k][x1][y1][x2][y2] = minv;
                    }
    double ave = (double)s[8][8] / n;
    
    double ans = sqrt(((double)f[n - 1][1][1][8][8] / n - ave * ave));
    
    printf("%.3lf", ans);
    
    return 0;
}
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看REaDME.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值