《算法竞赛入门经典》学习笔记与个人题解
记录个人学习《算法竞赛入门经典(第2版)》的个人心得,以及书上题目的个人题解及源码。
bughunter-
这个作者很懒,什么都没留下…
展开
-
UVA297 Quadtrees 解题报告
以用四分树来表示一个黑白图像,方法是用根结点表示整幅图像,然后把行列各分成两等分,按照图中的方式编号,从左到右对应4个子结点。如果某子结点对应的区域全黑或者全白,则直接用一个黑结点或者白结点表示,如果既有黑又有白,则用一个灰结点表示,并且为这个区域递归建树。p表示中间结点,f表示黑色(full),e表示白色(empty)。这题我们同样可以不需要显式建树,可以使用隐式建树的办法,先序递归解析四分树,一边解析一边统计,开一个二维数组标记所有被涂黑的像素点,用以在合并第二棵树的时候对描黑的像素点判重。原创 2024-04-12 10:58:02 · 373 阅读 · 0 评论 -
UVA699 The Falling Leaves 解题报告
先序递归隐式建树,同时统计每一列的和。我们并不需要真的建树,在递归的过程中我们无需知道每个节点的具体编号,只需要知道当前节点列编号即可,为了方便实现,我们将整棵树的根节点视为0列,往左为-1列,往右为+1列,这样做列数会有负数,所以使用map来维护每一列的和。给一棵二叉树,每个结点都有一个水平位置:左子结点在它左边1个单位,右子结点在右边1个单位。从左向右输出每个水平位置的所有结点的权值之和。如图6-7所示,从左到右的3个位置的权和分别为7,11,3。按照递归(先序)方式输入,用-1表示空树。原创 2024-04-11 16:23:11 · 292 阅读 · 0 评论 -
UVA839 Not so Mobile 天平 解题报告
采用递归(先序)方式输入:每个天平的格式为Wl,Dl,Wr,Dr,当Wl或Wr为0时,表示该“砝码”实际是一个子天平,接下来会描述这个子天平。当Wl=Wr=0时,会先描述左子天平,然后是右子天平。输入一个树状天平,根据力矩相等原则判断是否平衡。如图6-5所示,所谓力矩相等,就是WlDl=WrDr,其中Wl和Wr分别为左右两边砝码的重量,D为距离。判断结果的布尔值通过函数返回值返回,力矩值通过引用变量传出。这道题输入就采用了先序递归的方式,所以在实现的时候也可以采取先序递归的方式接收输入。原创 2024-04-11 09:21:18 · 443 阅读 · 0 评论 -
UVA210 并行程序模拟 解题报告
当一个程序的配额用完之后,把当前语句(如果存在)执行完之后该程序会被插入一个等待队列中,然后处理器从队首取出一个程序继续执行。当一个程序成功执行完lock指令之后,其他程序一旦试图执行lock指令,就会马上被放到一个所谓的阻止队列的尾部(没有用完的配额就浪费了)。当unlock执行完毕后,阻止队列的第一个程序进入等待队列的首部。等待队列用双端队列deque维护,阻止队列用普通的队列queue维护,cur[i]代表当前第i个子程序执行到第几行,val[]维护变量值,细节见注释和代码。原创 2024-04-10 15:25:32 · 379 阅读 · 0 评论 -
UVA230 Borrowers 图书管理系统 解题报告
首先输入若干图书的标题和作者(标题各不相同,以END结束),然后是若干指令:BORROW指令表示借书,RETURN指令表示还书,SHELVE指令表示把所有已归还但还未上架的图书排序后依次插入书架并输出图书标题和插入位置(可能是第一本书或者某本书的后面)。用map< string, int >维护书名与书的状态之间的映射,1为在书架,2为借出,3为归还但不在书架,剩下的就全都是按照题意硬模拟,用最纯粹的,最朴素的,最丁真(bushi)的循环遍历是足够AC的,也就懒得想优化了,细节很多,具体参考代码和注释。原创 2024-04-09 20:10:58 · 192 阅读 · 0 评论 -
UVA1596 Bug Hunt 找Bug 解题报告
因为存在嵌套,所以解析一个数组变量的值要用递归或者栈,用map维护数组名到数组信息结构体的映射,数组信息结构体应该包括数组的大小,以及该数组各个下标的值(用map< int, int >来记录)。数组定义,格式为arr[size]。例如a[10]或者b[5],可用下标分别是0~9和0~4。定义之后所有元素均为未初始化状态。赋值语句,格式为arr[index]=value。例如a[0]=3或者a[a[0]]=a[1]。程序不超过1000行,每行不超过80个字符且所有常数均为小于2^31的非负整数。原创 2024-04-09 19:59:32 · 614 阅读 · 0 评论 -
UVA1595 Symmetry 对称轴 解题报告
使用map< double, vector< double > > 将所有的点按照y轴分类存放,按y值一行行遍历所有的点,如果真的存在一个对称轴使得所有的点左右对称的话,那么这个对称轴的x坐标一定是任意一行相距最远的两个点的中间值(即他们的和除以2),这里我们就取第一行的最远两点求出中间值,然后遍历每一行的时候都从最靠外的两个点开始从外到内配对算他们的中间值,如果全部都等于同一个中间值,则确实存在这么一条竖线使得所有点左右对称。给出平面上N(N≤1000)个点,问是否可以找到一条竖线,使得所有点左右对称。原创 2024-04-09 19:27:05 · 236 阅读 · 0 评论 -
UVA12100 打印队列 解题报告
维护两个队列,一个普通的queue队列q,用于维护当前的打印机打印队列先后顺序,一个优先队列pq,用于维护当前的打印优先级。每次从q中出队一个文件,然后将其和pq的队首进行比对(也就是当前优先级最高的那个),优先级相同则代表现在要打印的就是这个(题目保证了每个文件的优先级唯一)。详细细节可见代码和注释。所有任务都需要1分钟打印。打印机的运作方式如下:首先从打印队列里取出一个任务J,如果队列里有比J更急的任务,则直接把J放到打印队列尾部,否则打印任务J(此时不会把它放回打印队列)。原创 2024-04-09 17:25:15 · 270 阅读 · 0 评论 -
UVA10391 Compound Words 复合词 解题报告
因为涉及查找效率,所以我们使用set对字符串进行存储,然后我们遍历set中的所有字符串,对于每个字符串s,我们枚举分割位置j,使用substr()方法将字符串s分割为左右两个子串,判断左右两个子串是不是都在set中即可。给出一个词典,找出所有的复合词,即恰好有两个单词连接而成的单词。输入每行都是一个由小写字母组成的单词。输入已按照字典序从小到大排序,且不超过120000个单词。输出所有复合词,按照字典序从小到大排列。原创 2024-04-09 17:01:20 · 522 阅读 · 0 评论 -
UVA10763 Foreign Exchange 交换学生 解题报告
有n(1≤n≤500000)个学生想交换到其他学校学习。为了简单起见,规定每个想从A学校换到B学校的学生必须找一个想从B换到A的“搭档”。如果每个人都能找到搭档(一个人不能当多个人的搭档),学校就会同意他们交换。每个学生用两个整数A、B表示,你的任务是判断交换是否可以进行。非常基础的map计数,map< pair< int, int >, int > 统计学校A到学校B交换的人数,然后统计所有B到A交换的人数是否和A到B的一样即可,详细见代码。原创 2024-04-09 16:42:23 · 231 阅读 · 0 评论 -
UVA10935 Throwing cards away I 卡片游戏 解题报告
桌上有n(n≤50)张牌,从第一张牌(即位于顶面的牌)开始,从上往下依次编号为1~n。当至少还剩下两张牌时进行以下操作:把第一张牌扔掉,然后把新的第一张牌放到整叠牌的最后。输入每行包含一个n,输出每次扔掉的牌以及最后剩下的牌。题目怎么说你就怎么做,非常直球,很显然是维护一个队列。原创 2024-04-09 16:31:50 · 357 阅读 · 0 评论 -
UVA1594 Ducci Sequence 解题报告
对于一个n元组(a1, a2, …重复这个过程,得到的序列称为Ducci序列,例如:(8, 11, 2, 7) -> (3, 9, 5, 1) -> (6, 4, 4, 2) -> (2, 0, 2, 4) -> (2, 2, 2, 2) -> (0, 0, 0, 0).也有的Ducci序列最终会循环。至于判断每次的序列是否为全0,用朴素的O(n)的循环遍历来判断肯定会超时,我们可以选择在模拟序列过程之前,先预设一个n个0的vector,然后每次就可以直接用==比较运算符来判断当前序列是否变成全0序列了。原创 2024-04-09 16:18:18 · 246 阅读 · 0 评论 -
UVA1593 Alignment of Code 代码对齐 解题报告
循环输入,每次输入用getline接收一整行,然后使用stringstream来分割单词,用vector< string > rowStrs[maxn]存储每一行的单词,因为需要对齐每一列的左边界并且要尽量靠左,所以在记录单词的同时我们要同时更新每一列单词的最大长度,在记录了所有的单词之后,按行依次输出所有的单词,每个单词的输出宽度设置为当前列最大单词长度+1即可做到题目要求的“对齐每一列的左边界,并且尽量靠左”。单词之间至少要空一格。每个单词不超过80个字符,每行不超过180个字符,一共最多1000行。原创 2024-04-09 15:04:29 · 396 阅读 · 0 评论 -
UVA221 Urban Elevations 城市正视图 解题报告
该算法“删除”相邻的重复元素,然后重新排列输入范围内的元素(其实并没有真正的删除元素,,并且返回一个迭代器(容器的长度没变,只是元素顺序改变了),表示无重复的值范围的结束(指向超出无重复的元素范围末端的下一个位置)。输入每个建筑物左下角坐标(即x、y坐标的最小值)、宽度(即x方向的长度)、深度(即y方向的长度)和高度(以上数据均为实数),输出正视图中能看到的所有建筑物,按照左下角x坐标从小到大进行排序。输入保证不同的x坐标不会很接近(即任意两个x坐标要么完全相同,要么差别足够大,不会引起精度问题)。原创 2024-04-09 14:42:24 · 348 阅读 · 0 评论 -
UVA814 邮件传输的代理交互 解题报告
(这里的用户列表set < string >是用来记录对应收件人是否存在的,在后续模拟连接到每个MTA后,要给这个MTA的哪些用户发送DATA,还是需要用到map>的)。对于每个请求,首先读入发件人,分离出MTA和用户名,然后读入所有收件人,根据MTA出现的顺序进行保存到vector中,并且去掉重复(跳过不放入列表即可)。接下来读入邮件正文,最后按顺序依次连接每个MTA,检查并输出每个收件人是否存在,如果至少有一个存在,则输出邮件正文。原创 2024-04-09 14:23:11 · 741 阅读 · 0 评论 -
UVA1592 DataBase 解题报告
直接写一个四重循环枚举r1,r2,c1,c2可以吗?理论上可以,实际上却行不通。每次碰到一个新的行r,把c1,c2两列的内容作为一个二元组存到一个map中。更值得推荐的方法是在主循环之前先做一个预处理——给所有字符串分配一个编号,则整个数据库中每个单元格都变成了整数,上述二元组就变成了两个整数。输入一个n行m列的数据库(1≤n≤10000,1≤i≤10),是否存在两个不同行r1,r2和两个不同列c1,c2,使得这两行和这两列相同(即(r1,c1)和(r2,c1)相同,(r1,c2)和(r2,c2)相同)。原创 2024-04-08 19:57:53 · 251 阅读 · 0 评论 -
UVA540 Team Queue 解题报告
每个团队可以建模为一个队列,而团队整体又形成一个队列。queue teamQue为团队的队列,记录团队整体的先后顺序,存放的是每个团队的编号,queue q[]存放的是各自团队成员的队列,q[i]代表的是团队i的成员队列。有t个团队的人正在排一个长队。每次新来一个人时,如果他有队友在排队,那么这个新人会插队到最后一个队友的身后。如果没有任何一个队友排队,则他会排到长队的队尾。输入每个团队中所有队员的编号,要求支持如下3种指令(前两种指令可以穿插进行)。对于每个DEQUEUE指令,输出出队的人的编号。原创 2024-04-08 19:31:23 · 335 阅读 · 0 评论 -
UVA12096 The Set Stack Computer 解题报告
为了方便起见,我们将每个不同的集合分配一个唯一的整数ID,则每个集合都可以表示成所包含元素的ID集合。剩下的就是根据题意模拟即可,集合的并集交集需要用到set的set_union()方法和set_intersection()方法。有一个专门为了集合运算而设计的“集合栈”计算机。该机器有一个初始为空的栈,并且支持以下操作。ADD:出栈两个集合,然后把先出栈的集合加入到后出栈的集合中,把结果入栈。INTERSECT:出栈两个集合,然后把二者的交集入栈。UNION:出栈两个集合,然后把二者的并集入栈。原创 2024-04-08 19:17:48 · 255 阅读 · 0 评论 -
UVA156 反片语 解题报告
在判断是否满足条件时,字母不分大小写”,也就是在忽略大小写的情况下每个单词的字母构成一样则算重复,要找出所有不重复的单词。所以我们在用map进行计数的时候,要先将单词“标准化”,将其都转换为小写字母,可以适用C++内置的函数tolower(),然后再将其按照字典序从小到大sort一遍,再放入map。把所有单词统计完之后,检查所有的单词,检查每个单词的“标准化”是否在map中只统计了一次,是的话就放入答案列表。输入一些单词,找出所有满足如下条件的单词:该单词不能通过字母重排,得到输入文本中的另外一个单词。原创 2024-04-08 16:27:38 · 350 阅读 · 0 评论 -
UVA101 木块问题 解题报告
从左到右有n个木块,编号为0~n-1,要求模拟以下4种操作(下面的a和b都是木块编号)。pile a onto b:把b上方的木块全部归位,然后把a及上面的木块整体摞在b上面。move a over b:把a上方的木块全部归位,然后把a放在b所在木块堆的顶部。move a onto b:把a和b上方的木块全部归位,然后把a摞在b上面。pile a over b:把a及上面的木块整体摞在b所在木块堆的顶部。遇到quit时终止一组数据。a和b在同一堆的指令是非法指令,应当忽略。原创 2024-04-08 16:03:15 · 164 阅读 · 0 评论 -
UVA1151 Buy Or Build 解题报告
https://vjudge.net/problem/UVA-1151平面上有n个点(1≤n≤1000),你的任务是让所有n个点连通。为此,你可以新建一些边,费用等于两个端点的欧几里德距离。另外还有q(0≤q≤8)个“套餐”可以购买,如果你购买了第i个套餐,该套餐中的所有结点将变得相互连通。第i个套餐的花费为Ci。最容易想到的朴素办法是先枚举购买哪些套餐,把套餐中的边权值都设为0,然后再求最小生成树。枚举量为O(2q),给边排序的时间复杂度为O(n2logn),Kruskal算法过程是O(n2),因此总复杂原创 2024-04-08 15:44:19 · 218 阅读 · 0 评论 -
UVA1395 Slim Span 解题报告
将边按照权值从小到大排序之后,如果一个连续边集[l, r]中的边可以使得n个点全部联通,则一定存在一个苗条度不大于e[r].w - e[l].w的生成树,枚举l和r。给出一个n(n≤100)结点的图,求苗条度(最大边减最小边的值)尽量小的生成树。原创 2024-04-08 11:00:12 · 243 阅读 · 0 评论 -
UVA821 Page Hopping 解题报告
最近的研究表明,互联网上任何一个网页在平均情况下最多只需要单击19次就能到达任意一个其他网页。如果把网页看成一个有向图中的结点,则该图中任意两点间最短距离的平均值为19。输入一个n(1≤n≤100)个点的有向图,假定任意两点之间都相互到达,求任意两点间最短距离的平均值。建模为边权为1的图,然后就是标准的floyd模板,注意处理一下自环边的问题即可,细节见代码注释。原创 2024-04-08 10:02:33 · 273 阅读 · 0 评论 -
UVA10048 Audiophobia 解题报告
对于任意一条至少包含两条边的路径i->j,考虑一个中间点k使得i->j的总长度等于i->k和k->j之和,此时已知路径i->k以及路径k->j各自的最大边权,那么显然i->j的最大边权是取他们的最大值。考虑不同的中间点k,结果可能不同,所以最后还需取一个最小值才是i->j的最佳路径(路径上的最大边权最小)。当噪声值太大时,耳膜可能会受到伤害,所以当你从某点去往另一个点时,总是希望路上经过的最大噪声值最小。输入一些询问,每次询问两个点,输出这两点间最大噪声值最小的路径(输出其最大噪声值即可)。原创 2024-04-07 15:27:36 · 338 阅读 · 0 评论 -
UVA247 Calling Circles 解题报告
初始输入的数据当中只知道两人是否有直接打电话,所以先用floyd求传递闭包,G[i][j]表示i是否直接或者间接给j打过电话,当且仅当G[i][j] = G[j][i] = 1时二者处于同一个电话圈,我们可以利用floyd传递闭包后的矩阵G[][]构建一个新图,仅当G[i][j] = G[j][i] = 1时连边,然后跑dfs依次输出各个联通分量。例如,a打给b,b打给c,c打给d,d打给a,则这4个人在同一个圈里;如果e打给f但f不打给e,则不能推出e和f在同一个电话圈里。细节请见代码和注释。原创 2024-04-07 13:55:15 · 511 阅读 · 0 评论 -
UVA10801 Lift Hopping 解题报告
在一个假想的大楼里,有编号为0~99的100层楼,还有n(n≤5)座电梯。由于本题在0层可以选择的电梯可能不止一部,那么起点可能也就不止一个,我们当然可以选择枚举起点算各自的单源最短路再找最小值,但这样不太优雅,比较低效(本题数据量不算大,这个方案也说不定能AC),我的方式是新建一个顶点编号为0,从0向所有的起点连一条边,将顶点0作为新的起点计算单源最短路,这样不会影响答案,还可以做到只跑一次Dijkstra。例如,有3个电梯,速度分别为10、50、100,电梯1停靠0、10、30、40楼,电梯2停靠。原创 2024-04-07 13:16:29 · 448 阅读 · 0 评论 -
UVA1001 Say Chesse 解题报告
考虑两个洞a和b之间的距离,假设他们的半径分别为r1和r2,因为洞内可以瞬移,所以a和b之间的距离为他们的欧几里得距离减去他们各自的半径,即sqrt((x[a] - x[b]) * (x[a] - x[b]) + (y[a] - y[b]) * (y[a] - y[b]) + (z[a] - z[b]) * (z[a] - z[b])) - r[a] - r[b],这个值可能小于等于0,小于等于0则代表两个洞相交,则视作距离为0即可。输入n个球的位置和半径,以及A和O的坐标,求最短时间。原创 2024-04-06 23:24:13 · 266 阅读 · 0 评论 -
《算法竞赛入门经典》第五章笔记与个人题解
本章主要介绍了算法竞赛中经常用到的C++特性与STL,还涉及了一些非常实用的技巧。以下是部分有重要意义例题的个人题解:例题5-2 木块问题 UVA101(关于题目描述请前往牛客竞赛网搜索题号)【分析】本题的核心数据结构是vector<int> pile[maxn],因为每个木块堆高度是不一定的,所以用vector来存储会非常合适,我们开辟一个vector的数组来存储每个木块堆上的木块编号,如pile[3]存放的就是3号木块堆上木块的编号。输入一共有4种指令,如果完全独立原创 2021-10-24 01:03:37 · 2016 阅读 · 0 评论