题意: 给定一个加权有向图,有n个点、m条边以及q条操作。q条操作中,有两种类型0 u表示将u点做上标记,1 u v表示计算u点和v的最短距离, 要求是最短路径上包括u、v的所有点都做上标记。 针对不同情况:
ERROR! At point x: 重复给x做标记则输出该语句。ERROR! At path x to y: 要求最短路的两端点并未全做上标记则输出该语句。No such path: 两端点都已做上标记,但是这两点间没有路。最短距离: 两点都已做上标记,并且两点间存在最短距离。题解: n ≤ 300,所以用Floyd也许能行 。但是Q ≤ 100000绝对不是令人好受的范围。我也是尝试了很久才找到的最佳办法。
多次Floyd: 这是毋庸置疑的,因为要求的最短路上的所有点都必须是做过标记的才行,所以每次有新的标记出现,我们都可能可以更新出新的最短路。但是原生的Floyd模板是不行的,三重循环的时间复杂度太高了。Floyd变形: 因此我们要尽量想办法让我们的Floyd适用这个题目,并且时间复杂度能够接受。办法是缩到二重循环。 可以回忆一下Floyd的核心思想是什么,是希望能在两端点u、v之间,找到一个中间节点k,使得u->k->v的距离小于u->v的直接距离。那么我们可以在每次给出一个新的标记k时,去更新所有经过k点的最短路。、标记: 然后你还可能会犯迷糊,虽然但是,按照上面的思路,我在更新的时候,最短路的两端没做过标记怎么办,需要避开不更新吗。答案是每当出现一个新的标记k,就去更新所有可能的最短路。 而为了应对更新的最短路中两端点是为标记的情况,我们只要在输出时另加判断即可。过程中犯的错:
三重Floyd: 办法还没考虑成熟就着急写代码了,所以才出现了上图的那么多错误。掌握Floyd的核心思想的话,改成二重循环即可完成题目。Floyd的位置: 有想过将Floyd放在什么位置(出现新标记时、询问两点最短路时)可能会省一些时间复杂度。实际上按照我们上面的思路,每出现一个新的标记,我们就要跑一边Floyd去更新我们的最短路。标记: 在我最初的Floyd函数中,我更新的最短路,所有的点都是做过标记的。这样是不行的,这样的更新是不会完整的。前面我说可能出现更新的最短路中两端点并未标记的情况,只要在输出之前判断两点如果做过标记,我就输出具体数值;如果并未做上标记,我就输出ERROR! At path x to y。