[区间动态规划] 棋盘分割

题目描述

​ 将一个8*8的棋盘进行如下分割:将原棋盘割下一块矩形棋盘并使剩下部分也是矩形,再将剩下的部分继续如此分割,这样割了(n−1)次后,连同最后剩下的矩形棋盘共有 n 块矩形棋盘。(每次切割都只能沿着棋盘格子的边进行)

​ 原棋盘上每一格有一个分值,一块矩形棋盘的总分为其所含各格分值之和。现在需要把棋盘按上述规则分割n块矩形棋盘,并使各矩形棋盘总分的平方和最小。

​ 请编程对给出的棋盘及 n,求出平方和的最小值。


输入

​ 第1行为一个整数n(1<n<15)。

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

输出

​ 仅一个数,为最小的平方和值。

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

数据规模与限定

时间限制:1 s

内存限制:64 M

解题分析

理解题意后,我们发现,我们每次只能横着切或者竖着切,并且切割下来的棋盘不能再次进行切割,然后题目要求我们去计算所有格子的分值之和的平方,这就考验了我们一个重要的思想,前缀和思想,如果我们每次都去一个一个地加和,那么时间必然消耗很多,所以这里考验我们会使用的第一个小技巧就是前缀和思想。我们不妨设定一个Val[i][j]的二维数组,表示从(1,1)到(i,j)的全部棋盘上的数值之和,根据这个定义,我们很快就可以得知,如果要求(i,j)到(k,l)区间上所有的格子分值总和的公式是Val[i][j]-Val[i][l-1]-Val[k-1][j]+Val[k-1][l-1]。这个公式其实不难理解,画个图就好理解了,我们首先减去(1,1)到(i,l-1)区间的数值和,在减去(1,1)到(k-1,j)的数值和 由于它们的交叉重叠部分Val[k-1][l-1]被我们减去了两次,所以最后我们加上这个值就好了。那我们如何创建一个前缀和数组Val[i][j]呢?首先,我们先读入当前(i,j)位置的值,然后再让,Val[i][j]+=Val[i][j-1]+Val[i-1][j]-Val[i-1][j-1] 所以说,为了防止数组越界和保证正确的计算读入,我们最好从i=1,j=1开始读入数据。

完成准备工作以后,再来审视一下这个题目,可以发现,我们要让棋盘剩下n块,就必须切割棋盘n-1次,那问题就来了,我们如何去思考这一过程的dp数组的更新和决策?又如何把它和一大堆子问题联系在一起呢?其实,第一刀切割的位置是有限的(横着切,m行有m-1种切法,竖着切,p行有p-1种切法),所以说,我们枚举第一刀切割的位置即可,切下的这一大块就是n块中的一块,所以设定一个函数f(i,j,k,l,num)表示切割(i,j)到(k,l)位置,使得棋盘变成num块的最小平方和值。边界条件就是num=1的时候,这个时候直接返回棋盘的平方和的值就好了,所以一个记忆搜索法的程序就出来了。

代码实现1
#include <iostream>
using namespace std;int n,board[9][9]={0};
int dp[10][10][10][10][16]={0};int V(int k,int l,int i,int j){return board[i][j]-board[i][l-1]-board[k-1][j]+board[k-1][l-1];
}int S(int x){return x*x;
}int f(int i,int j,int k,int l,int p){if(p==1){return S(V(i,j,k,l));}if(dp[i][j][k][l][p]) return dp[i][j][k][l][p];int ans=1e9,val1,val2;for(int m=j;m<l;m++){val1=f(i,j,k,m,1)+f(i,m+1,k,l,p-1);val2=f(i,j,k,m,p-1)+f(i,m+1,k,l,1);ans=min(ans,min(val1,val2));}for(int m=i;m<k;m++){val1=f(i,j,m,l,1)+f(m+1,j,k,l,p-1);val2=f(i,j,m,l,p-1)+f(m+1,j,k,l,1);ans=min(ans,min(val1,val2));}dp[i][j][k][l][p]=ans;return ans;
}int main(){scanf("%d",&n);for(int i=1;i<=8;i++){for(int j=1;j<=8;j++){scanf("%d",&board[i][j]);board[i][j] += board[i-1][j] + board[i][j-1] - board[i-1][j-1];}}int result=f(1,1,8,8,n);printf("%d\n",result);return 0;
}

当然啦,直接用for循环打表也是一个很好的选择,而且不太容易爆栈空间。

首先,程序使用一个二维数组val来存储棋盘格子的分值,并使用前缀和的方式计算出每个格子左上方区域的分值和。这样可以在后续计算中快速获取任意矩形棋盘的总分。

然后,程序使用一个五维数组dp来动态规划地计算平方和的最小值。数组dp[t][k][l][i][j]表示将棋盘分割为t块矩形棋盘时,在区域(k,l)(i,j)之间的平方和的最小值。

接下来,程序使用嵌套的循环遍历所有可能的矩形棋盘区域,并计算出对应的平方和。初始状态下,当t=1时,直接计算出每个矩形棋盘的平方和。

然后,程序通过动态规划的方式计算出将棋盘分割为t块矩形棋盘时的最小平方和。对于每个t,通过遍历所有可能的切割位置,将棋盘切割为两个子区域,然后使用之前计算得到的结果dp[1][k][l][i][c]dp[t-1][k][c+1][i][j](或dp[t-1][k][l][i][c]dp[1][k][c+1][i][j])计算出当前状态的最小平方和。通过遍历所有切割位置,找到最小的平方和,并将结果存储在dp[t][k][l][i][j]中。

最后,程序输出dp[n][1][1][8][8],即将整个棋盘分割为n块矩形棋盘时的最小平方和。

这种动态规划的解决方法可以有效地解决棋盘分割问题,并找到平方和的最小值。

代码实现2
#include <iostream>
using namespace std;int val[9][9],n,dp[16][10][10][10][10]={0};int V(int k,int l,int i,int j){return val[i][j]-val[i][l-1]-val[k-1][j]+val[k-1][l-1];
}int S(int x){return x*x;
}int main(){scanf("%d",&n);for(int i=1;i<=8;i++)for(int j=1;j<=8;j++){scanf("%d",&val[i][j]);val[i][j]+=val[i-1][j]+val[i][j-1]-val[i-1][j-1];}for(int i=1;i<=8;i++)for(int j=1;j<=8;j++)for(int k=i;k<=8;k++)for(int l=j;l<=8;l++){dp[1][i][j][k][l]=S(V(i,j,k,l));}for(int t=2;t<=n;t++)for(int k=1;k<=8;k++)for(int l=1;l<=8;l++)for(int i=k;i<=8;i++)for(int j=l;j<=8;j++){int ans=1e9;for(int c=l;c<j;c++){int val1=dp[1][k][l][i][c]+dp[t-1][k][c+1][i][j];int val2=dp[t-1][k][l][i][c]+dp[1][k][c+1][i][j];ans=min(ans,min(val1,val2));}for(int c=k;c<i;c++){int val1=dp[1][k][l][c][j]+dp[t-1][c+1][l][i][j];int val2=dp[t-1][k][l][c][j]+dp[1][c+1][l][i][j];ans=min(ans,min(val1,val2));}dp[t][k][l][i][j]=ans;}printf("%d\n",dp[n][1][1][8][8]);return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/313131.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Leetcode每日一题:1599.经营摩天轮的最大利润

前言&#xff1a;本题是一道逻辑细节题&#xff0c;考察阅读理解并转化为代码的能力&#xff0c;很多细节 题目描述&#xff1a; 你正在经营一座摩天轮&#xff0c;该摩天轮共有 4 个座舱 &#xff0c;每个座舱 最多可以容纳 4 位游客 。你可以 逆时针 轮转座舱&#xff0c;但…

声明式导航传参详情

1 动态路由传参 路由规则path ->/article/:aid 导航链接 <router-link to"/article/1">查看第一篇文章</router-link> 组件获取参数: this.$route.params.aid 如果想要所有的值&#xff0c;就用this. $route. params 注意&#xff1a;这两个必须匹配…

STM32的在线升级(IAP)实现方法:BOOT+APP原理详解

0 工具准备 Keil uVision5 Cortex M3权威指南&#xff08;中文&#xff09; STM32参考手册 1 在线升级&#xff08;IAP&#xff09;设计思路 为了实现STM32的在线升级&#xff08;IAP&#xff09;功能&#xff0c;通常会将STM32的FLASH划分为BOOT和APP两个部分&#xff0c;BOO…

[每周一更]-(第46期):Linux下配置Java所需环境及Java架构选型

Linux下配置Java所需环境及Java架构选型 一、配置基础环境 1.配置tomcat 环境变量 wget https://dlcdn.apache.org/tomcat/tomcat-10/v10.1.8/src/apache-tomcat-10.1.8-src.tar.gz tar -zxvf apache-tomcat-10.1.8-src.tar.gz 在/etc/profile 末尾追加export CATALINA_HOME…

排序算法-选择插入排序

文章目录 排序算法-选择插入排序 排序算法-选择插入排序 /// <summary>/// 选择插入排序/// Krystal 2023-11-10 09:02:06 每一次找一个最小的放到正确的位置上/// 直接选择排序通过每一轮的比较&#xff0c;找到最大值和最小值&#xff0c;将最大值的节点和右边交换&…

【快速全面掌握 WAMPServer】10.HTTP2.0时代,让 WampServer 开启 SSL 吧!

网管小贾 / sysadm.cc 如今的互联网就是个看脸的时代&#xff0c;颜值似乎成了一切&#xff01; 不信&#xff1f;看看那些直播带货的就知道了&#xff0c;颜值与出货量绝对成正比&#xff01; 而相对于 HTTP 来说&#xff0c;HTTPS 绝对算得上是高颜值的帅哥&#xff0c;即安…

【STM32】SPI通信

1 SPI通信 SPI&#xff08;Serial Peripheral Interface&#xff0c;串行外设接口&#xff09;是由Motorola公司开发的一种通用数据总线 四根通信线&#xff1a;SCK&#xff08;Serial Clock&#xff0c;串行时钟&#xff09;、MOSI&#xff08;Master Output Slave Input&am…

使用anaconda创建爬虫spyder工程

1.由于每个工程使用的环境都可能不一样&#xff0c;因此一个好的习惯就是不同的工程都创建属于自己的环境&#xff0c;在anaconda中默认的环境是base&#xff0c;我们现在来创建一个名为spyder的环境&#xff0c;专门用于爬虫工程&#xff1a; //括号中名字&#xff0c;代表当…

初识大数据,一文掌握大数据必备知识文集(7)

&#x1f3c6;作者简介&#xff0c;普修罗双战士&#xff0c;一直追求不断学习和成长&#xff0c;在技术的道路上持续探索和实践。 &#x1f3c6;多年互联网行业从业经验&#xff0c;历任核心研发工程师&#xff0c;项目技术负责人。 &#x1f389;欢迎 &#x1f44d;点赞✍评论…

大数据 - Hadoop系列《三》- HDFS(分布式文件系统)概述

&#x1f436;5.1 hdfs的概念 HDFS分布式文件系统,全称为:Hadoop Distributed File System。 它是一个文件系统&#xff0c;用于存储文件&#xff0c;通过目录树来定位文件&#xff1b;其次&#xff0c;它是分布式的&#xff0c;由很多服务器联合起来实现其功能&#xff0c;集…

Java集合/泛型篇----第五篇

系列文章目录 文章目录 系列文章目录前言一、说说LinkHashSet( HashSet+LinkedHashMap)二、HashMap(数组+链表+红黑树)三、说说ConcurrentHashMap前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通…

miniqmt配置

1 下载安装qmt 2 将安装目录下的 xtquant 目录复制到 python安装目录 的相同路径下 3 测试 from xtquant import xtdata def on_data (datas):#回调函数 print(datas) seq xtdata.subscribe_whole_quote(code_list[‘002306.SZ’], callbackon_data) time.sleep(10) xtda…