ACM大学生程序设计竞赛在线题库最新精选题解(赵端阳)解析

在线OJ题库部分解析


测试网站主要为书中ZOJ,HDOJ。如果你准备入门acm,那以下题目顺序循序渐进,很适合各个阶段新手刷题。

非常感谢本书作者和编审人员,后悔没有早点看到此书,相见恨晚!在此推荐一波希望更多像我一样的小白能从中受益受益。

章节(完结)

  • 前言
  • 第1章基础编程技巧题
  • 第2章模拟编程技巧题
  • 第3章字符串处理技巧题(缺)
  • 第4章大整数运算技巧题
  • 第5章基本数据结构题
  • 第6章搜索算法题
  • 第7章动态规划算法题
  • 第8章贪心算法题
  • 第9章回溯算法题
  • 第10章图论算法题
  • 第11章几何题(缺)
  • 第12章数学题(缺)
  • 完结撒花


前言

本书介绍:ACM大学生程序设计竞赛在线题库最新精选题解
本书OJ入口:HDOJ、ZOJ

说实话我觉得新手确实需要一份刷题单,带解析那种书。我个人也是新手才开这本书的题。我觉得写完读别人代码有很大提升,但是看题解大多数oj并不支持阅读其他人ac代码,而且很难找到优秀的代码。这本书给的代码让我学会很多奇技淫巧
这本书题单大多不错而且基本难度递增,本文主要为了指出书中部分不当之处。(仅为个人意见)


提示:本书为当前最新版(2019年7月出版)

第1章基础编程技巧题


本章基本水题,但是对新生来说必不可少,可以增强信心 ,可以把基本功打牢,比如sum总是忘初始化0,输出格式不对,二分边界总写错等等常见bug(虽然我也总wa在奇奇怪怪的点

HDOJ1056-HangOver:此题推出公式应该没什么问题,掌握浮点输出应该不会错。值的注意的是int/int还是int,所以以后有double时吧所有整型常数都变成xx.0形式。
并不推荐,可以参考下题练习:PATL3-013非常弹的球题解。

HDOJ1735-字数统计:此题出的有点烂,但是没刷过模拟题的可以试试,实际上有两种情况题解没有考虑到,应该是出题人的锅,可以改进一下算法,参见HDOJ1735-字符统计题解,不必要再用一遍for循环记录空白数,直接第一次读入时用index记录最后一行最后有字的位置即可。

ZJU1058-Currency Exchange:并不推荐。

ZJU1067-Color Me Less:并不推荐。

ZJU1078-Palindrom Numbers:强烈建议新手不看书写一遍,然后看书题解,再独立写一遍。,简单的回文判断和进制转换至少不能超过3分钟写完,简单题都要调试半天的话那比赛中难题会更卡。

ZJU1090-The Circumference of the Circle:不建议写,思维题。

ZJU1095-Humble Numbers:丑数,建议看书后能独立完成,毕竟赛场过不了的题打表是基本操作。

ZJU1105-FatMouse’s Tour:题意较怪,可以一试,不过书中代码有坑,大多数测评机c++已经不支持gets(),书中代码用C(gcc 6.5.0)编译可以AC。此外书中%dist应为印刷错误,应该是%d。参见ZJU1105-FatMouse’s Tour题解

ZJU1151-Word Reversal:简单题,新手建议写写。

ZJU1154-Niven Numbers:水题,建议新手看书后独立完成。

第2章模拟编程技巧题


本章算是正式入门第一步,模拟题需要考虑的特殊情况较多,比赛一个特殊点过不了都算wa,所需要的代码能力要求较高。写模拟可以训练补充漏洞以及造数据能力。可以学一下acm对拍数据。

HDOJ1035-Robot Motion:模拟题,新手可以一试。

HDOJ猜数字:暴力循环1000-9999即可。新手随便写写。

HDOJGrey Area:书中印错一处,图2-1应为图2-2。鉴于没有源码参考发篇题解:HDOJGrey Area题解

HDOJ-Scaring the brid:可以用深搜但没必要,数据很小,建议按书上做法枚举所有状态,最多210,尝试一下状态压缩做法。另外本题有一个坑点即judge函数的s从0开始,因为有测试数据是所有稻草人位置占了整个图,这样0个也可以过。

HDOJ-ArcSoft’s Office Rearrangement:思维题,但是值得试试。

ZJU1003-Crashing Balloon:因数分解,递归做法。建议独立写写。

ZJU1006-Do the Untwist:凯撒密码,很水,看心情写~

ZJU1016-Parencodings:建议独立完成,看完题解可以再试试。

ZJU1039-Number Game:本题出的很突兀,可以顺便学一下博弈论的sg函数。本题还需要记忆化搜索和状压。建议写完第六章回过头来补这个题。

ZJU1042-W’s Cipher:还是凯撒密码,稍微复杂点,可以试试。

ZJU1051-A New Growth Industry:纯模拟,可以练手。

ZJU1056-The Worm Turns:本章第一道大型模拟题,可以试试,但是赛场说实话基础不牢还是没信心开这种大型模拟的。

ZJU1057-Undercut:并不推荐,很无聊的题。

ZJU1073-Round and Round We Go:循环数,很有意思。可以模拟试一遍然后写后面数学做法。膜北大大佬,硬是把模拟题写成数学题。%%%

ZJU1088-System Overload:约瑟夫环,不要模拟了,太水了,推一下后面公式然后写递归做法,书上for循环版本也行,但建议再试试递归。不过本题有个坑点是1号楼永远先断,所以序号建议自己推下。

ZJU1098-Simple Computers:学了计组可以试试本题。

ZJU1144-Robbery:纯模拟,可以试试。

ZJU1160-Biorhythms:同余定理,建议模拟试一遍后学学中国剩余定理,网上讲的感觉好复杂,实际就是两数加最小公倍数同余
a%m=b%m表示成a≡b(mod m)。本题中设 x≡p(mod 23);x≡e(mod 28);x≡i(mod 33);这样推出 p+=23满足(p-e)%28=0时p满足前两个方程,以此类推。

第3章字符串处理技巧题(缺)


本章前后关联性不大,建议跳过本章从第四章开始。如果你刷PAT那当我没说,高校机试确实有很麻烦的处理字符串问题。

本章不做说明。

第4章大整数运算技巧题


本章题并不多,建议全部写一遍,熟练掌握高精乘即可。

HDOJ2940-Hex Factorial: 高精阶乘,保存结果打表即可。原书程序可以优化一下,详见HDOJ2940高精度阶乘优化版。

ZJU1205-Martian Addition: 进制20的高精度乘法。本章没什么好说的,可以参考洛谷高精度与模拟题单。

ZJU1210-Reciprocals: 建议独立完成。不过书上代码是假的,样例都过不了还ac?。思路没问题,但是去掉末尾0后精度long long远远不够,还需要大整数模拟。参考题解:ZJU1210-Reciprocals题解。

ZJU1962-How Many Fibs?:斐波那契大整数模拟。打表判断,书上思路很好倒着存补‘0’然后用strcmp比较。当然也可以用int型数组存结果然后自己写个比较函数。本题也建议独立完成。

第5章基本数据结构题


本章旨在熟悉基本的STL,本章题量仍很少,不熟悉STL的同学可以边学边写,熟练的就直接跳过本章。

HDOJ3682-To Be an Dream Architect: 给各个点编号即可,不断加入vector中然后去重,书上代码可以理解为给x轴赋权值n2,给y权值n,给z赋权值1,相当于独立编号。还不懂的同学建议百度一下哈希是什么。

ZJU1004-Anagrams by Stack: 本题出在本章难度显得略高,但递归一定是入门最需要克服的坎。本题dfs便是不断搜索的过程,初学递归往往难点之一是不知道递归的参数是什么,会递归但不会写递归。我也是学了很久才渐渐熟练会写递归。参数往往是每次前进一个状态的变化的量,更简单的找出其中参数是找到最终需要用来判断边界的量,每次传递下一个状态的参数即可。

ZJU1061-Web Navigation: 用到stack的简单模拟,不熟悉的试试stack用法,熟悉跳过即可。

ZJU1062-Trees Made to Order:了解组合数学应该是能看明白题解的,组合数学著名的三个数列:Fibonacci、Stirling、Catalan。建议不懂的小白学下组合数学,机器学习绕不过组合数学的。本题用到卡特兰数,不懂具体怎么分析是看不懂题解在说什么的,觉得难的同学可以先跳过本题,学完9章再回过头看其他博客学习卡特兰数用递归写。虽然网上确实没有适合新手的组合数学题解

ZJU1094-Matrix Chain Multiplication:还以为是动态规划,结果是简单递归。递归思路不难,就是每次把括号里两个矩阵算出相乘次数再转化成新矩阵,每次跳出括号不断累加。不过书上STL这个思路也很巧妙,相当于直接算成括号匹配了,用栈实现,本题类似逆波兰数,可以递归建树O(nlogn)也可以用堆栈实现O(n)算法。

ZJU1097-Code the Tree:说实话我也看不懂这个标程怎么实现的。但思路就是不把它当成树建图,而是当作无向连通图来存。然后不断输出最小的单节点,至于每次选中最小的点就用priority_queue实现,最小堆能在O(1)时间内求出最小数。本题值得一写。

ZJU1156-Unscrambling Images四叉树的递归,题目有点费解,看一遍很难明白题目在说啥。大致意思就是第一块输入压缩的四叉树编号, 第二个输入对应位置的颜色号。

第6章搜索算法题


刷完本章可以说算是入门半只脚了,本章建议新手全写一遍,打好基本功。
搜索的复杂度较高,所以难点不在于递归而在于剪枝,务必注意本章的各种剪枝操作。

HDOJ1010-Tempter of the Bone:很典型的深搜加剪枝题,广搜只能得到最短路所以不行(不明白为什么的同学建议这里开始学简单的数据结构知识),奇偶剪枝也不难,写上总没坏处

HDOJ1016-Prime Ring Problem:同样用奇偶判别剪枝,因为数字序列从1开始,如果是奇数个连续的数,就,一定会凑出一个至少和大于4的偶数。

HDOJ1175-连连看:建议本题bfs和dfs都做一遍,虽然书上没有剪枝,但实际上本题可以简单剪枝一下,即转弯两次后如果和终点不在一条线上那就没有必要往下试了。可以试一下这个剪枝,只需要一个判断条件return就行。另外bfs和dfs是基本功,像本题这种难度,至少半小时之内写完改完bug然后AC.如果感觉不熟练多写几遍,当然dfs写法有很多,可以像书上for外标记点,for内判断,也可以for外return判断边界,for内到下一层标记等等,多敲敲就能手熟(真肌肉记忆

HDOJ1241-Oil Deposits:很经典() 的题,值得一试。

HDOJ1242-Rescue:本题思路比较巧妙,反向搜索。另外注意如果是求最短路类型的题,dfs的复杂度虽然理论上和没有优化的bfs一样,但因为有回溯,所以时间一般是不用优先队列的bfs时间的两倍,虽然dfs好写,但其实带优先队列priority_queue的bfs也没有那么难,多练就熟悉了。dfs和bfs时间复杂度O(n2),而最小堆优化的bfs是O(nlogn),比赛求最短路能用bfs就不要用dfs。

HDOJ1312-Red and Black:没有剪枝,和那道非常经典的油田题差不多,书上只给了dfs的代码,仍建议用bfs再写一遍。

HDOJ1539-Shredding Company:dfs,书上题解是标记空格位置然后迭代,递归每个起点即可。不过要注意的一点是题目说的是原数字不能有前导零,但是分割的数字是可以有前导零的
参考最后一个样例:

6 1104
rejected

即可以分为1,1,0,4或1,1,04。所以没必要特判0能不能作为起点。

HDOJ2266-How Many Equations Can You Find:和上题类似,递归标记分隔变成加减号而已。同样分隔的数字可以有前导零,没必要特判。

HDOJ2952-Counting Sheep:这题应该出在前面,简单的连通块,相信如果刷完前面的题,那本道用dfs或bfs写都不会超过5分钟,有木有感觉进步很大(笑)。

HDOJ4403-A very hard Aoshu problem:比之前题稍难,思路就是枚举等号位置然后分别对两边进行搜索。本题的预处理很巧妙:

//ch[]为输入字符串
for (int i = 0; i < len; i++)
			for (int j = i; j < len; j++)
				for (int k = i; k <= j; k++)
					a[i][j] = a[i][j] * 10 + ch[k] - '0';
//例如ch=1212
//则a[][]={
//1 12 121 1212
//0 2 21 212
//0 0 1 2
//0 0 0 2
//}

可以把 a [ i ] [ j ] a[i][j] a[i][j]理解为起点为i终点为j的数字。

ZOJ1002-Fire Net:dfs,不断试当前位置加一,所以只需要判断之前位置即可。题解的时间复杂度还是很高(才发现不会证,貌似是NP问题,但至少比O(n!)大,比O(2n2)小),但n最多为4,所以这么写完全够了,优化的话,我只能想到剪枝判断条件和寻找下一个位置可以优化,但没有更好的思路。本题类似八皇后问题。如果有更好的思路请踹我(评论私信均可)。

ZOJ1008-Gnome Tetravex:本题实际上是从左向右,从上向下填方格,每次只需要判断左边和上边方格是否满足。剪枝操作是记录重复的类型,没有这个优化会超时,即把格子的类型和数量记录下来,不用判断重复类型。

ZOJ1047-Image Perimeters:本题较简单,因为题目明确内部没有孔,意味着内部没有周长,只需要算外边周长即可,本题无优化。唯一会难考虑的点是如何计算周长,实际上只考虑外边,那么对每一个格子‘X’,搜索四个方向格子,如果是‘X’就继续搜,如果是’.‘边长就加一。然后搜索四个对角有无连通的’X’即可。所以我们再最外层加一圈’.'就很容易判断。如果你学图像处理的话就知道卷积图片时这种补零操作很常见简单的,需要记住这种做法。

ZOJ1075-Set Me:判断条件较复杂,但就是简单的枚举。

ZOJ1079-Robotic Jigsaw:本题不留坑,就是我不会写。。。。

ZOJ1084-Channel Allocation:着色问题,参考图的m着色问题:借用一张图说明:
ACM大学生程序设计竞赛在线题库最新精选题解(赵端阳)解析_第1张图片
节点可以看做站台,不同频道意味着不同颜色相邻,由于转发器位于水平面内,所以说这个图一定是一个二维的平面图。它不会像克莱因瓶那样跳到另一个四维时空内然后连接回来(哈哈哈原谅我这个颇大的脑洞)。所以说连线不会交叉,意味着这是二维平面,对于完全平面图来说,离散数学证明过四色问题,也就是说我们至多用四个颜色就能将图渲染的每个节点与其他节点颜色不相邻,感兴趣的可以搜一下这个问题,原本是由画地图时以颜色区分不同国家得到的这个问题。

ZOJ1091:原题本来为国际象棋的一道题,该题流传甚广,洛谷过河卒一题也是一种变式。需注意骑士移动是走日字步的,否则相邻走完全没必要尝试路径,直接有固定解。本书罗列了三种方法,dfs和bfs建议都尝试一下(很奇怪我用bfs写wa了,不知道没有考虑什么特殊情况。)另一种方法floyd算法,这个算法很简单,三重循环,即对节点i和j,如果有一个中间跳板节点k,能使i到k加k到j的距离小于i到j的距离,我们就替换掉这个距离,当然这是一种打表的做法,可以尝试。(虽然比赛用不到这么费时的算法)

ZOJ1136-Multiple本题一定要写!!!
关于分支界定算法可以参考分支界定算法,对本题来说解空间很多,但我们只需要得到一个最小解即可,按照升序数字尝试就一定能得到最小解。所以说bfs对每个节点依次下搜,形象考虑,即二叉树的每个下一层一定会比本层多二倍,所以越往下搜索越好事。而本题为m叉树的解空间尝试,利用广搜可以一层一层尝试。找到最小解就返回所以很快。另外本题的优化需要学会,因为我们要找到模N的最小公倍数,所以余数一定不会超过N的范围(0-5000),我们每次只需要判断这5000个余数曾经有没有被尝试过即可,这样搜索的次数就会大大减少。
另外不懂为什么要用余数除的建议看看模的性质。对本题来说:假如前缀数是M,前缀数M模N的余数是R(即 M m o d N ≡ R M mod N≡R MmodNR),我们在前缀M后补一位数字A再次尝试时:
即求 M ∗ 10 + A m o d N M*10+A mod N M10+AmodN的结果,而由于模的性质可得:
( M ∗ 10 + A ) m o d N = ( M ∗ 10 ) m o d N + A m o d N = ( R ∗ 10 ) m o d N + A m o d N = ( R ∗ 10 + A ) m o d N (M*10+A) mod N=(M*10)mod N +A mod N=(R*10) mod N+A mod N=(R*10+A)mod N (M10+A)modN=(M10)modN+AmodN=(R10)modN+AmodN=(R10+A)modN

ZOJ1148-The Game:唉,本章最后一题还是中规中矩的,终于结束了。有两个点需要注意:一是题目中步数segment指的是直道数而非经过的空格数。所以说最短路用bfs时需要把同一个方向的格子全部搜索完。二是本题的gets只能用c编译,如果用c++需要用cin.getline()函数读入数据,而且之前一定要有getchar(),否则cin.getline()会先读取缓冲区的换行符。


第7章动态规划算法题


本书排版算比较好的,动态规划需要前面递归分治的知识才能写。动态规划和递归两者都是把大问题分成类型相同的小问题,但动态规划子问题间解决方案相互联系,而递归子问题可以互不影响。动态规划满足两个特点,其一是大问题可以分解为相同的小问题,小问题存在最优解,其二是整体问题最优解依赖各个子问题的最优解。

HDOJ1087-Super Jumping! Jumping! Jumping!:很入门的一道动态规划!排版确实不错,但是书上题解完全错了,代码是对的,你可以看出题解和代码前言不搭后语。书上题解是最长递增子序列算法,而不是最大递增子序列算法。题解如下:

定义dp[i]为以a[i]结尾的最大递增序列和。
初始化: d p [ i ] = a [ i ] dp[i]=a[i] dp[i]=a[i] 1 ⩽ 1\leqslant 1 i ⩽ n \leqslant n n
如果 a [ i ] > a [ j ] a[i]>a[j] a[i]>a[j] d p [ i ] = m a x ( d p [ i ] , d p [ j ] + a [ i ] ) dp[i]=max(dp[i],dp[j]+a[i]) dp[i]=max(dp[i],dp[j]+a[i]) 1 ⩽ 1\leqslant 1 i ⩽ n \leqslant n n 0 ⩽ 0\leqslant 0 j ⩽ i \leqslant i i

HDOJ1231-最大连续子序列:本题公式虽然用b数组记录j结尾的最大连续和,但实际上只用了一个sum来不断更新,这实际上就是滚动数组优化。不懂的同学再看看博客讲解,往后写就会慢慢理解了。另外本题思路不难,但是题解好像很复杂的样子,实际上就是一直求前缀和,如果是正的就继续加,如果是前缀和是非正的,那说明不要前面的项,序列和才能更大。

HDOJ1257-最少拦截系统:题解写的很清晰,我们更新每个系统拦截的最小的,如果比其中的小那就更新,如果没有那就另开一个系统。这样系统数一定是最小的(想想为什么)。

HDOJ1505-City Game:这道题排版极其不合适,应该排到下一题,有了1506的基础才好写本题。本题相当于把二维的图转换为一维的1506题。对于每一行,求面积最大的值。本题转换思路很巧妙。

HDOJ1506-Largest Rectangle in a Histogram:好题!比赛见过类似的题,想了很久无果,居然看见原版题了!本题思路:枚举每一个高度计算面积,难点是确定该高度究竟能扩展到多宽?确定边界需要动态规划的思想,我们分别确定每一个高度的左右边界。比如左边界,我们用dpl[i]表示第i个高度的左边界。第一个已经不能再往左边扩展了,即dp[1]=1,而之后的高度如果比边界高度低(或相等),那说明还能继续往左扩展,那继续扩展到该边界高度的边界判断,右边界同理。然后枚举每一个高度去算面积即可,需注意高度乘宽度的值需要long long型保存。

HDOJ1520-Anniversary party:树形dp入门题,没有上司的舞会,最简单最基本的树形dp,写完可以再试试洛谷的树与图上的动态规划,其中二叉苹果树也是很经典的一道树形dp。

HDOJ1864-最大报销额:01背包问题,先排除不符合要求的发票,然后直接代一维数组dp的公式即可。本章需要详细了解原理,建议看其他参考书或者博客弄清楚原理。这里推荐一个最简单的01背包入门,带图理解会很清楚:01背包问题。不过这个讲解的是最基本的二维数组dp,本题是优化的一维数组dp。背包问题有个很有名的博客:背包九讲。其中第一讲 01背包问题建议参考。

HDOJ1950-Bridging signals:很经典的LIS,网上讲解很多,不做说明。

HDOJ1978-How many ways:记忆化搜索和动态规划思路都一样,都是从当前节点出发所能到达的节点内继续走下去,加上父节点的路径方式数。不过需注意动态规划是从初始状态开始迭代,而搜索是从底部开始返回值。所以动态规划初始 d p [ 1 ] [ 1 ] = 1 dp[1][1]=1 dp[1][1]=1;而记忆化搜索需要把终点 d p [ n ] [ m ] = 1 dp[n][m]=1 dp[n][m]=1

HDOJ2167-Pebbles:本状态压缩方式思路较难考虑,把每一行的所有状态都迭代下去。博主能力有限不做细考。

HDOJ2197-Computer:又是树形dp,实际上画一个图尝试一下就很清晰,现有结论:从任意一点u出发搜索到的点一定是树的直径s,t中的一点。所以首先随便从一个点开始dfs,找到最远点就一定是s,t中的一点,然后在从s或t中一点dfs找到另一点t或s,这时两端的距离基本上就是最长路径,可是直径中间引申出的节点保存的dist值不一定是最长路径。所以再搜索一遍就能得到最后答案,之所以不能用 m a x ( d i s t [ t ] − d i s t [ x ] , d i s t [ x ] ) max(dist[t]-dist[x],dist[x]) max(dist[t]dist[x],dist[x])求,是因为该节点不一定在直径上。

HDOJ2476-String painter:本题非常经典,网上讲解也很多就不所费口舌了, d p [ i ] [ j ] dp[i][j] dp[i][j]表示 i − j i-j ij间的字符串操作数,不懂为什么从j外循环的可以参考这个空串变成原字符串的dp:qsc54(区间dp)。还不懂手写一下或者打印一下中间变量就明白为什么这么推了。

HDOJ2602-Bone Collector:01背包,优秀的讲解太多了,我就不献丑赘述了。另外我感觉书中二维数组的代码写的很奇怪,因为没有判断j和weigh[i]大小情况下就直接引用,这样的话数组角标大部分情况都是负的。当然如果是负的,那这个值不会被用到,但一般写法应该如下:

for (int i = 1; i <= n; i++) {
			for (int j = 0; j <= vol; j++) {
				if (j >= w[i])dp[i][j] = max(dp[i-1][j], dp[i - 1][j - w[i]] + v[i]);
				else dp[i][j] = dp[i - 1][j];
			}
		}

HDOJ2955-Robberies:逃跑概率不能直接计算所以需要用金币dp。另外逃跑概率只能通过1-抓捕概率方便计算。

HDOJ3001-Travelling:TSP问题,三进制压缩有点难想。

HDOJ3450-Counting Sequences:树状数组+dp。本题不会,不留坑,不补题。

HDOJ3530-Subsequence:枚举最长序列的右边界,找到满足条件的左边界即可。

HDOJ3689-Infinite monkey theorem:了解kmp算法细节就能dp出来。

HDOJ4359-Easy Tree DP?:书上解析有问题,实际上是因为指数序列有这样一个特征, 2 0 + 2 1 + . . . + 2 n − 1 < 2 n 2^0 + 2^1 + ... + 2^{n-1} < 2^{n} 20+21+...+2n1<2n所以只要把最大的放在右子树就永远满足。分两种情况,一种是只存在左右子树情况,另一种是都存在情况,具体参考HDU 4359 Easy Tree DP?。书上的推论有误。

HDOJ4374-One hundred layer:经典dp,但是书上推论有误,dp[i][j]表示到达第i层j格的最大分值时,从第k个下来左向右走j最大值是 p [ i ] [ j ] = m a x ( d p [ i − 1 ] [ k ] + s u m [ i ] [ j ] − s u m [ i ] [ k − 1 ] ) p[i][j] = max(dp[i-1][k] + sum[i][j] - sum[i][k-1]) p[i][j]=max(dp[i1][k]+sum[i][j]sum[i][k1]),但是从k下来后从右向左走到j应该是 d p [ i ] [ j ] = m a x ( d p [ i − 1 ] [ k ] + s u m [ i ] [ k ] − s u m [ i ] [ j − 1 ] ) dp[i][j] = max(dp[i-1][k] + sum[i][k] - sum[i][j-1]) dp[i][j]=max(dp[i1][k]+sum[i][k]sum[i][j1])。如果每一层的j都要枚举k的话就会超时,所以用队列维护j两边t步内的最大值。维护队首最大,每次从队尾入队,并保证单调性(把小的删掉),并把队首不在t步范围内的删掉即可。

HDOJ4571-Travel in time:题目较难,书上记忆化求节点最大满意度,也可以用dp实现。因为用floyd处理后每个点已经是最短的,只用考虑价值与时间,相当于01背包问题。不懂可参考:hdu 4571 Travel in time (floyd+分组背包)。当然书上剪枝做法会更快。

HDOJ5418-Victor and World:TSP问题变形。如果你真正明白floyd的松弛操作意义,你就能懂这个dp是怎么实现的。压缩所有的状态,由于城市可以重复访问,所以用floyd求出每个节点间的最短路,然后从小枚举每个状态,枚举每个状态的节点进行松弛操作。

HDOJ5773-The All-purpose Zero:简单LIS算法,因为要求严格递增,所以需要减去前面0的个数防止0等于该值导致不严格。因为0可以变成任何数,所以无论如何0都能在最长序列中。

第8章贪心算法题


之所以这章题不难,是因为这章标题叫做贪心算法题。由于标题的字面含义,所以我们已经知道这些题贪心可解。然而平时做题却不会的原因在于我们并不知道题目能不能用贪心去做。所以本章重在搞明白能为什么题目能用贪心,需要清楚原理。

HDOJ1598-find the most comfortable road:由于道路是双向的所以可以用kruskal算法。从小到大贪心选择边。学过数据结构的最小生成树应该能懂本题思路。

HDOJ1789-Doing Homework again:由于每个作业不论分值大小多少完成都需要一天,所以显然在作业能完成的天数内从大到小完成是最优的。不明白如何证明的可以思考这个思路。假设每个作业的截止日期都是昨天。那么总的惩罚分是一定的,所以在截止日期内我们应该依次从中取最大的分数来抵消总的惩罚。

hdoj1912-Highway:本题和下一题解法思路相似。用勾股定理求出每个点在公路上所建出口范围的最左和最右点,然后对最左点排序,如果相等,排最右点。然后类似动态规划题的导弹拦截系统,如果超出范围就出口+1并更新起点,否则只需要缩小右边界范围即可。

HDOJ2037-今年暑假不AC:和上题一样的思路,本题属于难者不会会者不难系列。按结束时间排序,贪心选取。活动安排问题,线段区间覆盖问题都是一样的贪心思路。可以参考:活动安排问题(贪心)。如果对其原理想更深了解,这里建议看一下刘汝佳的算法入门经典(紫书)的第八章8.4.2贪心法-区间相关问题,里面有详细的解说和证明,就不在此赘述了。

HDOJ2544-最短路:单源求最短路dijkstra算法,模板题没啥好说的,但是不建议用书上这个代码,没有堆优化是 O ( n 2 ) O(n^2) O(n2),建议找个堆优化的 O ( n l o g n ) O(nlogn) O(nlogn)模版。

HDOJ2570-迷瘴:体积相同就是贪心,不同就是背包。很简单的贪心。

HDOJ2863-Top Shooter:实际上是用贪心算法的大型模拟题。原理不难,写不出来说明还是手生,代码能力不过关。需要加油写写简单模拟题找出自己平时写代码的不规范操作。比如命名混乱导致自己写条件判断时变量搞错等等。

HDOJ2904-Warfare:思路不难,用所有边长的和减去最大生成树即可。为什么?因为生成树树加上任何一条边就会形成环,数据结构基础知识。所以总和一定,就要让生成树的边尽可能的大。构造边权值等具体实现见书上所写。

HDOJ3177-Crixalis’s Equipment:典型贪心题,需要推倒一下两个物品应该优先选谁,后面很多题都是一样的原理。

HDOJ3697-Selecting courses:同样的活动安排问题模版,按结束时间选即可。唯一不同是需要考虑间隔5分钟需要每个间隙尝试。

HDOJ3730-Chain:与其说是贪心不如说是简单模拟。

HDOJ3979-Monster:很经典的题目,但书中排序与其用除法不如用乘法,由于精度问题,除法显然没有乘法精确。这里给出更好的写法,另外这里推一下为什么要这样排序。对于攻击力m的v11来说,假如有个怪兽A和B,A的血量 H p a Hp_a Hpa,攻击力 G a G_a Ga,由于攻击是离散的,那么杀死怪物A的时间是一个向上取整的数字 T a = c e i l ( H p a / m ) T_a=ceil(Hp_a/m) Ta=ceil(Hpa/m)。同理A的血量 H p a Hp_a Hpa,攻击力 G a G_a Ga,杀死所需要时间 T b = c e i l ( H p b / m ) T_b=ceil(Hp_b/m) Tb=ceil(Hpb/m)。所以先杀死A后杀B耗血量为: ( G a + G b ) ∗ T a + G b ∗ T b … … 1 (G_a+G_b)*T_a+G_b*T_b……1 (Ga+Gb)Ta+GbTb1同理先杀死B后杀A耗血量为: ( G a + G b ) ∗ T b + G b ∗ T a … … 2 (G_a+G_b)*T_b+G_b*T_a……2 (Ga+Gb)Tb+GbTa2要使耗血量从小到大排,即1式减2式要小于0。可以得到: T a ∗ G b < T b ∗ G a T_a*G_bTaGb<TbGa所以我们的结构体和比较函数可以这么写:

const int N = 10005;
struct node {
	int hp, g, t;
	bool operator < (const node &x) const {
		return t * x.g < x.t*g;
	}
}monster[N];

HDOJ4221-Greedy?:题目名称很有意思,Greedy?显然就是Greedy。最大值最小或者最小值最大问题,一般都是贪心+二分。本题题目求的是最大的惩罚值最小而不是所有惩罚之和最小。所以仍是贪心选取。请自行推导。

HDOJ4296-Buildings:同上题,求最大值最小问题。推导见书中所写。

HDOJ4415-Assassin’s Creed:本题书上解析和代码都非常详尽。不赘述。

HDOJ4647-Another Graph Game:思路很巧妙的题,把边权分到两个节点不会影响最后的结果。因为如果边上的两个点是不同人,那么他两分数的差值是不会变,如果是一个人,那么这个人分数的和值也不会变化。

HDOJ4726-Kia’s Calculation:从高位到低位,从9到0枚举这一位,a和b中是否有满足的两个数相加为此数,第一位需要特判,只能从9到1枚举,如果找不出来说明只能输出0。书中代码还可以优化一下,在遍历除了第一位后,其余位时直接遍历。实际上应该统计一下数字长度,如果打印的数字够了就说明不用继续循环下去了,因为再循环a和b的桶排序数组已经全部为0了。

HDOJ4864-Task:因为分数为 500 ∗ x + 2 ∗ y 500*x+2*y 500x+2y,而y取值0-100。所以排序任务应该先从大到小排x的顺序在排y。机器排序同理,时长排好后,只要第k个时间够处理,那么k之前的也够处理,选取这k个中等级最小的即可。

HDOJ5821-Ball:一开始以为水题,只要判断l到r区间内,a数组和b数组各个元素种类及个数是否一样即可。但后来发现每个区间可以交叉,所以只能排序来做。书中算法可以再改进一下,如果在b中元素查找a次数没有超过n,说明a,b里面各个数字的个数对应不上,那无论如何都转换不了。

第9章回溯算法题


本章较第六章略难。可以参考刘汝佳《算法竞赛入门经典第二版》第7章暴力求解法讲解如何从暴力到枚举排列,从生成子集到回溯法。

HDOJ1015-Safecracker:典型搜索题,只能不断尝试,算出每个字典序得到的值是否为答案。由于答案需要打印字典序最大的那个序列,所以对字母集从大到小排序,搜索出答案直接返回即可。新手建议独立写一遍这个优化后的算法。如果还是有问题可以参考HDOJ1015-Safecracker优化版。

HDOJ1181-变形课:和上题类似暴力搜索,首字母b开始搜,搜到结尾m就跳出搜索。

HDOJ1258-Sum It Up:因为元素可以重复,而且以非递增的方式排序,所以可以用pre记录前一次搜索的开头元素来避免重复。当然也可以桶排序以桶的个数搜索。

HDOJ1456-Transportation:题意比较乱,基本就是搜索每个订单接受还是拒绝。遍历完后抽出其中最大的。另外书上解释3有误。d是发票序号,但是val应该是累积到当前的接受订单收入的总和。

HDOJ1584-蜘蛛牌:应该是区间dp,没想到这题怎么搜索状态,不得不说写出dfs的还真是个天才,实际上10不用动,而1-9牌只能放在对应大一号的牌上。所以枚举每一张牌作为起始移动搜索,dfs返回时候自然就又重新枚举下一个起始移动了。

HDOJ1627-Krypton Factor:最巧妙的不是回溯构造字符串,而是如何判断是否有重复。实际上还是dp思想,因为前cur-1个字符是合法的,只需要判断加入第cur后是否合法即可,类似八皇后问题(参考下一题)。因此从第cur位到中间位尝试比较前面相等长度字符串即可。文字不好说明,建议自己画图尝试。另外书中代码有误,只用

if(--n==0){...  return;}

这么判断是是错的,这样n为负值还会继续遍历下去导致回溯无法结束。应该在dfs(cur+1)后继续返回。还是不懂的话请参考:HDOJ1627-Krypton Factor。

HDOJ2553-N皇后问题:著名回溯算法八皇后问题。网上讲解很多不赘述。

HDOJ4228-Flooring Tiles:本题转换问题思路很巧,拼出m种不同矩形所需方块n满足n有2* m或者2* m-1个约数即可。但题解最后好像写错了。求出最小反素数n,使约数个数为2* m或者2* m-1。本题剪枝操作也很绝,各种剪枝卡时间。

HDOJ4499-Cannon:八皇后问题变体。唯一不同是判断当前的棋子是否合法的判断条件变了。如果你理解八皇后问题那本题也不难。

HDOJ4536-XCOM Enemy Unknown:原理不难,就是题目要求很琐碎。单纯每次搜索帮助哪个国家,但是对其他国家影响和恢复现场比较麻烦,模拟题刷多了应该不会怯场。

HDOJ4770-Lights Against Dudely:和上题类似,仍是暴搜模拟题。

HDOJ5004-KAMI:还是模拟题,功力浅薄,写不下去。

HDOJ5355-Cake:解法意想不到,算是数学题了吧。可以参考:hdu5355 思维+爆搜。

HDOJ5723-Abandoned country:问题转化太巧妙了,第一问求最小花费显然时最小生成树,而第二问求最大预期,期望值=任意两点路径之和/路径总数。而路径总数是定值 = n ∗ ( n − 1 ) / 2 =n*(n-1)/2 =n(n1)/2,而任意两边边权不一样,最小生成树是唯一的,期望值唯一,求边的总和不从点考虑,而从边考虑,因为树不存在环,所以一条边左边点到右边点必然经过此边,对于每条边的总和,就是左边点数乘右边点数乘边权。问题变成递归求叶子节点个数。

HDOJ5887-Herbs Gathering:01背包,递归写法。先贪心排序然后各种剪枝。没有更好的思路这里不做评价。

第10章图论算法题


本章作为了解基础图论算法题已经足够。由于本人能力有限,本章给不出更好思路,具体参考书中解析。

HDOJ2962-Trucking:队列优化的Bellman-Ford,二分高度每次计算。虽然此算法经常被卡,但非图论选手了解已经够了。

HDOJ3018-Ant Trip:欧拉回路是可以一笔画完的,用查并集维护这个回路的连通图即可。

ZJU1060-Sorting It All Out:拓扑排序算法,难写。

ZJU1186-Street Directions:将图中的所有桥拆为两条反向的单向边,Tarjan算法求强联通分量。

ZJU1197-Sorting Slides:二分图匹配求关键边。模板题,书上用的prim算法,网上博客很多,不提。

ZJU1203-Swordfish:最小生成树算法,kruskal稀疏图,prim稠密图。

ZJU1221-Risk:Floyd打表,没啥好说的,之前第六章就写过。

ZJU1232-Adventure of Super Mario:遇到类似题型好多了,最短路加一个可以跳过的操作,更像是一个DP题。

ZJU1542-Network:还是最小生成树。。。

ZJU1935-XYZZY:由于有负权边,所以用SPFA求最短路。

ZJU2797-106 miles to Chicago:还是最短路算法,只不过路径权值不再是加而是乘。

Efficient Codes:不会,不留坑。

ZJU3010-The Lamp Game:不留坑+1。

第11章几何题(缺)


不做评价。


第12章数学题(缺)


博主只了解简单的组合排列算法,只看了刘汝佳紫书第10章数学概念初步,能力不足,不做说明。


完结撒花

2021.6.6记
本书除3,11,12章外可以短期内作为新手入门学习试题(请无视博主8个月才更完 )。博主从新手时期也是刷着本书一路走来,从开始的递归写几小时还一直wa,到现在有了思路基本一遍ac;从当初写代码不知道从何下手,到如今能清晰冷静分析思路实现。
虽然因为实验课设等等原因拖了很久学完,但现在也勉勉强强算入门了。不过由于个人原因刚入门就得说再见了。尽管最后什么荣誉也没得到,但我并不后悔这份没有结果的努力。

你可能感兴趣的:(本科,acm,算法,acm竞赛)