图论一般题合集
病毒溯源
题意:给定一棵树,求出最大深度,要求输出字典序最小的路径
Solution:由于看错题,以为是dag,然后发现只需要拓扑排序一下然后dp最长路就可以了。但值得注意的是需要提前对邻接表排序保证字典序,每次更新都需要维护终点,必须在过程中维护。我们找的是后缀最大值,但希望前缀结构最小。
1 | vector<int>e[N]; |
Solution:每当发现需要拓扑序dp的时候就应该想到记忆化搜索,如果发现是树可能想到的比较快。
1 | vector<int>e[N]; |
送外卖https://www.acwing.com/problem/content/description/4477/
题意:给定一棵树,每次给点集加一个点,求从根出发到达当前点集所有点至少一次的最短总路程
Solution:对于这种每次都与上一次问题有细微变化的题目,我们考虑微观分析。然而我们发现依旧难以下手,因为我们的终点不确定,就完全没有确定的推理根基。。考虑对称性:加强题目条件,要求每次都要回到根。
按照加强题目的条件来考虑,对于当前点集的所有的点,我们最多走向他一次,离开一次,显然这样贪心是最优的,所有相关边最多会走两次,回到原问题我们需要钦定一个终点使得答案尽可能减少,选择深度最大的点即可。
实现方面:我们可以预处理所有点的深度,方便更新钦定终点,每次我们只需要对于新加进来的点考虑需要哪些新边,这些边只会走两次,以后就不用统计他们了,所以需要记忆化搜索,每次让新点向根跳,直到跳到已经统计过的边,考虑整个过程不难想到上面的边也已经统计过了。
1 | int fa[N]; |
千手观音https://www.acwing.com/activity/content/code/content/3586865/
题意:每个字符串代表一个数,连起来能够代表进制数,按大小顺序给出一些字符串组合起来的进制数,现在让你给这些字符串排序,如果存在不确定关系,字典序小的在前面。
Solution:首先明确这个关系具有传递性,可以证明,于是我们只需要相邻比较去建边.其次考虑两个位数不同的进制数是无法比较的(eg. 189和145.999)。我们只需要把能比较的第一位不同的建立边。用优先队列完成拓扑排序去满足字典序最小。
实现:我们需要哈希表去将字符串映射,用get函数将一个进制数的几个字符串全部拆成vector,便于我们处理,剩下的操作全都是基本图论。
debug:为了保证所有涉及到的字符串都会参与拓扑排序,我们需要在哈希表种创建他们。但是只创建一次,第二次再赋值为0会覆盖之前的入度信息。
1 | unordered_map<string,int>din; |
给一颗基环树,请你输出所有环上的点。
Soluton1.考虑拓扑排序的思想,由于是无向图所以每个点至少出度为1,环上的点至少度为2,所以就只是偏移了入队标准,其他和拓扑排序一摸一样
1 | vector<int>e[N]; |
Solution2.考虑并查集找环,第一次合并失败的时候,必然这两个点都在环上。不加这个边,原图变成树,两个点之间的路径唯一,直接维护父节点一路倒退回去,或者对节点标记,再扫一遍。这里用set是偷懒了
1 | vector<int>e[N]; |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 爱飞鱼的blog!
