一本通_1197:山区建小学(尚贤)

2023-11-08 11:30
文章标签 一本 小学 山区 1197 尚贤

本文主要是介绍一本通_1197:山区建小学(尚贤),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

【题目传送门】

话不多说,推荐超级好文一篇

**

注意留意作者标黑的几个类,确定子问题设计状态、状态转移方程、确定边界值、确定实现形式、确定优化方法。===》》 多么经典的dp流程。。

还有作者在这个过程中各种的引导,觉得这是看过以来最好的dp文章。
并且这个还是 区间dp 的经典例题。值得深入学习!!

**

▍题目分析

这道题乍一看,似乎没有什么思路,那么就先返璞归真,先想想怎么打暴力求解这道题吧。在m个村庄中要建立n个小学,先不考虑时间复杂度,那么我们可以先当成m中取n个的时间复杂度求出所有情况,再进行暴力算出每一种情况的距离和,再比较出最小的,在只会用递推时,我们似乎就只能这么去做,但是这种暴力的方法显然是很慢的,过题几乎不可能,那么在这种想法的基础上,加入动态规划的思想,问题将会迎刃而解。

那么先想想动态规划的本质和作用,动态规划只是一种思想,并不是一种写法,它的本质就是降低问题的规模(说白了就是经过优化之后的暴力算法),在节约问题的规模的同时除去冗余计算以节约时间。但是这道题很不好想,也很难和动态规划联系起来,还涉及到区间dp,状态转移方程也是一大难点(小编也琢磨了半天)。为了大家的理解方便(理解万岁!),那么就分模块讲解。

动态规划的一般步骤包括确定子问题、设计状态、写出状态转移方程、确定边界条件、确定实现方式、确定优化方法(似乎本题不需要),那么就逐一思考。

确定子问题:

这道题的子问题没有那么麻烦,直接一想就出来了,比如说现在的问题是m个村庄中选n个建小学,那么我们可以考虑在前m个村庄中选n-1个的情况,可以考虑在前m个村庄中选n-2个的情况,也可以考虑在前m-1个村庄中选n-1个的情况,……这些都是原问题的子问题。

设计状态:

按照刚才所划分的子问题,我们可以自然的想到状态是什么,定义数组f[ i ][ j ]为当在前i个村庄中建立j个小学的最小路程和,那么原问题(在m个村庄中选n个建小学)的答案就是f[ m ][ n ],这样问题就涉及好了。

状态转移方程:

写这个状态转移方橙方程,是比较难的,首先假装我们已经算出了每两个村庄之间建立一个小学的最短距离和,并把这些数据存在数组c[ i ][ j ],那么我们就知道了村庄i到村庄j这个区间内建一个小学的最短距离和,先不要考虑我们是怎么算出来的;


举个栗子:比如现在有5个村庄,现在我们正要通过动态规划更新f[ 3 ][ 2 ]的值,先画个草图:

在这里插入图片描述
因为我们只需要选2个,那么我们为了达到目的更新f[ 3 ][ 2 ]的值,我们会不择手段,就算再来一层循环也在所不惜(情况需要),再来一层循环那么我们就从1到3遍历前三个村庄,那么我们会不停枚举每一个村庄为边界(也就是说这个村庄及所有它左边的村庄最近的小学在它的左边,而右边的所有村庄都不会去左边的小学去上学,因为已经有更近的了)的情况,找到一个最小值,然后更新f[ 3 ][ 2 ],详见图示:
在这里插入图片描述
此时三个村庄被划分成了两部分,当只有2个村庄建小学时,这就意味着蓝色部分建2-1个小学,也就是前1个村庄中建1所小学(即f[ 1 ][ 1 ]);而在绿色部分只建1所小学,也就是村庄2和村庄3内建1个小学的最短距离和,即c[ 2 ][ 3 ];当然,将蓝色部分最短距离和和绿色部分最短距离和加起来,就是f[ 3 ][ 2 ]的值啦,但这还不一定是最小的,所以还有考虑以2,3为边界时的值,选一个最小的。如果到此还是不理解,可以停下来利用画图工具来接着模拟以2,3为边界的情况。


类比以上的栗子,如果用i,j,k来表示当以k为边界时前i个村庄选j个建小学(即以k为边界时的f[ i ][ j ]值),那么状态转移方程则可以表述为f[ i ][ j ]=min( f[ i ][ j ],f[ k ][ j-1 ]+c[ k+1 ][ i ] );也就是所有f[ k ][ j-1 ]+c[ k+1 ][ i ] 中最小的那个。我感觉表达的还行吧,如果不理解一定要画图。

确定边界条件:

这个似乎没有什么问题吧,一直更新到f [ m ][ n ]就可以了,然后输出它的值;初始赋值的式子为f[i][1]=c[1][i];,这个很容易理解吧,无论如何前i个村庄中建一个小学时,都等于1到第i个村庄只建一个学校的最短距离和,这不正是我们上文中所假装求出的吗?只要i from 1 to m赋f的初值就可以了。

确定实现形式:

动态规划的实现形式主要就两种:记忆化搜索和数组递推,这里使用数组递推的形式。

确定优化方法:

貌似没有。

实现方法

Part one

我们分开来写这道题,先写简单的,定义一大堆变量,变量作用,见上文。

1 int m,n,a[1000][1000],c[1000][1000],f[1000][1000];

最好在main函数外边定义,那样初值就全是0了。

Part two

很平凡而没有技术含量的输入……

1 cin>>m>>n; 2 for(int i=1;i<m;i++) 3 cin>>a[i][i+1];

Part three

还记得吗?我们当初假装我们已经知道了每两个村庄之间建立一个小学的最短距离和,而我们现在就要面临怎么真正算出来这个问题了,为了算出每两个村庄之间建立一个小学的最短距离和,那么我们首先要知道这两个村庄的距离吧,求距离代码如下:

1 for(int i=1;i<=m;i++)
2 for(int j=i+1;j<=m;j++)
3 a[i][j]=a[j][i]=a[i][j-1]+a[j-1][j];
  它这个算法和floyed很像,在学这之前,希望身为大牛的您先学会floyed,这样理解就很方便了。核心思路就是使原来未知距离的i,j两点通过j-1这个点来过渡刷新距离的值,如果画画图,举个栗子,就很清晰明了了。

Part four

算出了距离,那么我们就可以开始算我们假装知道的距离和了。举个栗子,比方说要在3~6这个区间内建一所小学,那么你会选几号村庄呢?当然是选中间的!(3+6)/2=4,所以建在4号村庄,这是为什么呢?先假设在3号村庄建,那么将如下图所示:
  在这里插入图片描述
因为4,5,6都去3号村庄上学,所以总路程将会是3黄+2红+1*绿。但是如果4号村庄建小学呢?

在这里插入图片描述

因为3,5,6都去4号村庄上学,所以总路程将会是1黄+2红+1*绿。相比来说少走了一段距离,接着5,6号村庄建小学也以此类推,同时会发现由于区间内一共有偶数个村庄,所以4,5都在中间,且距离和一样,所以两者均可。

那么这样我们就明确了怎么知道哪一个村庄该建小学,然后就能求出每两个村庄之间建立一个小学的最短距离和了。代码如下:

复制代码
1 for(int i=1;i<=m;i++)
2 for(int j=i+1;j<=m;j++)
3 {
4 int mid=(i+j)/2;
5 for(int k=i;k<=j;k++)
6 c[i][j]+=a[k][mid];
7 }
复制代码

Part five

那么现在就要正儿八经开始动态规划了,先得赋初始值了吧……

1 for(int i=1;i<=m;i++) 2 f[i][1]=c[1][i];

Part six

利用之前得到的状态转移方程,通过数组递推一步一步得到结果,代码如下:

复制代码
1 for(int i=1;i<=m;i++)
2 for(int j=2;j<=n;j++)
3 {
4 f[i][j]=999999;
5 for(int k=j-1;k<=i;k++)
6 {
7 f[i][j]=min(f[i][j],f[k][j-1]+c[k+1][i]);
8 }
9 }
复制代码

Part seven

输出结果……

1 cout<<f[m][n];

对,这道题做到这里就完了,这道题还是很不好理解的,需要多看,小编在写博客的时候也多次犯蒙。

#include<iostream>
#include<cmath>
using namespace std;
int m,n,a[1000][1000],c[1000][1000],f[1000][1000];
int main()
{cin>>m>>n;for(int i=1;i<m;i++)cin>>a[i][i+1];for(int i=1;i<=m;i++)for(int j=i+1;j<=m;j++)a[i][j]=a[j][i]=a[i][j-1]+a[j-1][j];for(int i=1;i<=m;i++)for(int j=i+1;j<=m;j++){int mid=(i+j)/2;for(int k=i;k<=j;k++)c[i][j]+=a[k][mid];}for(int i=1;i<=m;i++)f[i][1]=c[1][i];for(int i=1;i<=m;i++)for(int j=2;j<=n;j++){f[i][j]=999999;for(int k=j-1;k<=i;k++){f[i][j]=min(f[i][j],f[k][j-1]+c[k+1][i]);}}cout<<f[m][n];return 0;
}

这篇关于一本通_1197:山区建小学(尚贤)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/369564

相关文章

uva 11044 Searching for Nessy(小学数学)

题意是给出一个n*m的格子,求出里面有多少个不重合的九宫格。 (rows / 3) * (columns / 3) K.o 代码: #include <stdio.h>int main(){int ncase;scanf("%d", &ncase);while (ncase--){int rows, columns;scanf("%d%d", &rows, &col

【简历】25届南京某一本JAVA简历:简历通过率还好,但是拿不到OFFER

注:为保证用户信息安全,姓名和学校等信息已经进行同层次变更,内容部分细节也进行了部分隐藏 简历说明 今天看一份25届南京某一本大学的Java简历。 这个简历呢,学校是一本。我们说上来先要定校招层次,这个层次就按照中厂来讲。因为现在很多的双非一本目标都是在中厂。 这个同学有个实习经历,一本有八成的同学主项目都是重复的。HR他只能看到项目重不重复,要点对不对他不知道,就从这个角度来看,这位同学

【简历】25届重庆某一本JAVA简历:比赛项目描述都是无用的废话

注:为保证用户信息安全,姓名和学校等信息已经进行同层次变更,内容部分细节也进行了部分隐藏 简历说明 这是一个重庆某一本大学25届硕士的Java简历,这个简历,其实还是有一定东西的,然后我们说这个,这是一个重点类的一个一本,所以我们说就按照大厂来讲,但是,其实这后面的这个项目经历不行,就按大厂来讲吧,但是这个按大厂的话,这个学校在大厂里面是最差的一个背景了,他是个减分项,项目这块呢,优势不强啊,

小学科学骨干教师课堂教学展示活动总结

虽然我已经有八年的教龄了,但是作为一名小学科学老师,我还是一名刚入门的学生。抱着需要迫切学习的心态,我在11月27日参加了市教育局教研室组织的“xx市小学科学骨干教师课堂教学展示活动”。   在这次活动中,6位上课教师无不使出浑身解数,使得课堂教学精彩纷呈、高潮迭起,而之后评课老师的精彩点评更让我有醍醐灌顶之感。   其中,中山小学xx老师的一堂《运动起来会怎样》让我的印象尤其深刻。姜瑜老

如何构建小学至大学素质评价档案系统 —— php Vue 实践指南

🍊作者:计算机毕设匠心工作室 🍊简介:毕业后就一直专业从事计算机软件程序开发,至今也有8年工作经验。擅长Java、Python、微信小程序、安卓、大数据、PHP、.NET|C#、Golang等。 擅长:按照需求定制化开发项目、 源码、对代码进行完整讲解、文档撰写、ppt制作。 🍊心愿:点赞 👍 收藏 ⭐评论 📝 👇🏻 精彩专栏推荐订阅 👇🏻 不然下次找不到哟~ Java实战项目

基础算法--递推算法[信奥一本通]

本节所讲题源自【信奥一本通】C++版:基础算法-第三章-递推算法 相信大家应该都接触过数列的概念。哎哟,一直在跟数组打交道,说数列感觉好陌生,哈哈。数列中的迭代法大家都还记得吗:通过反复应用特定规则,推导出某一点起始的连续的后续数列。 我们的递推也是这样,给出一些初始值,从题目中找出后续数据应该与已知数据存在哪些关系,能不能写出一个公式或者经过同种操作进行反复推导,得出结论。在数学中

一本读懂数据库发展史的书

数据库及其存储技术,一直以来都是基础软件的主力。数据库系统的操作接口标准,也是应用型软件的重要接口,关系重大。 作为最“有感”的系统软件,数据库的历史悠久、品类繁多、创新活跃。 对数据库历史发展的介绍,有利于新一代技术人员的学习和传承;对未来演进的探究,有利于数据库开发者的思考和实践。 如果想对当今数据库体系有一个深入的了解,最好学习一下数据库的发展史。这对于在我们脑海里建立数据库体系的知识

C++题解(23) 信息学奥赛一本通:1026:空格分隔输出

【题目描述】 读入一个字符,一个整数,一个单精度浮点数,一个双精度浮点数,然后按顺序输出它们,并且要求在他们之间用一个空格分隔。输出浮点数时保留6位小数。 【输入】 第一行是一个字符; 第二行是一个整数; 第三行是一个单精度浮点数; 第四行是一个双精度浮点数。 【输出】 输出字符、整数、单精度浮点数和双精度浮点数,之间用空格分隔。 【输入样例】 a122.33.

【简历】25届青岛某一本JAVA简历:中厂不要强调算法,面试官听不懂

注:为保证用户信息安全,姓名和学校等信息已经进行同层次变更,内容部分细节也进行了部分隐藏 简历说明 今天我们要看的是一位来自25届青岛某一本硕士同学的Java简历。 依旧是先判断自己要投什么层次的厂,也就是我们校招第一法则:定层次。 因为在不同的层次,面试官的要求,考察的时间点和内容都不太一样。 一本的话,我们大多定在中厂,在一线城市薪资在一万到一万五左右。 但有些比较好的理工类或者是

如何用GPT写一本玄幻爽文小说?轻松上手

如果要写一本玄幻爽文小说,你完全可以用GPT来帮忙,这可是一条捷径。无论是创造奇妙的世界观,设计角色,还是编写剧情,我们都可以用GPT快速推进创作。下面就是一份实操教程,从构思到完成一本玄幻爽文,手把手教你如何用GPT搞定! 1. 构思故事的核心:背景设定与主线 步骤1:确定世界观 玄幻爽文的魅力在于其独特的世界观,比如修真世界、魔法大陆、异能都市等等。利用GPT生成背景设定,可