存在一个有向图(不一定连接),其中一个或多个节点被区分为源。可从任何一个源访问的任何节点都被视为“已点亮”。 现在假设其中一条边被移除。问题是确定先前已点亮且不再点亮的节点。
我认为可以考虑类似城市电力系统的类比。
答案 0 :(得分:7)
这是一个“动态图形可达性”问题。以下文章应该是有用的:
A fully dynamic reachability algorithm for directed graphs with an almost linear update time. Liam Roditty,Uri Zwick。 计算理论,2002。
这给出了一个算法,其中包含O(m * sqrt(n)) - 时间更新(摊销)和O(sqrt(n)) - 可能循环图上的时间查询(其中m是边数和n节点数)。如果图形是非循环的,则可以将其改进为O(m)时间更新(摊销)和O(n / log n)时间查询。
考虑到问题的具体结构,或者通过时间交换空间,你总是可以做得比这更好。
答案 1 :(得分:1)
如果不是“点亮”或“不点亮”,您将保留一组节点从其供电或点亮的节点,并将具有空集的节点视为“未点亮”,并将节点视为非空设置为“lit”,然后删除边缘只会涉及从目标节点的集合中删除源节点。
编辑:忘了这个: 如果你移除了集合中的最后一个lit-from-node,则遍历边缘并删除你刚刚从它们的集合中“解开”的节点(也可能从那里遍历,依此类推)EDIT2(改为tafa): 首先:我误读了原来的问题,并认为它表明,对于每个节点,已经知道它是点亮或不点亮的,现在我重新阅读它,没有被提及。
但是,如果您网络中的每个节点都存储了一个包含其被点亮的节点的集合,您可以轻松地从删除的边缘遍历图形并修复任何点亮/不亮的参考。 因此,例如,如果我们有节点A,B,C,D像这样:(对ascii艺术的跛脚尝试)
A -> B >- D
\-> C >-/
然后在节点A,你会存储它是一个源(并因此自己点亮),并且在B和C中你将存储它们被A点亮,而在D中你会存储它被两个点亮A和C.
然后说我们将边缘从B移到D:在D中我们从点亮源列表中移除B,但它仍然点亮,因为它仍然被A点亮。接下来说我们在A之后将边缘从A移到C即:A从C的集合中删除,因此C不再点亮。然后我们继续遍历起源于C的边缘,并从D的集合中移除C,现在也是未点亮的。在这种情况下,我们已经完成了,但如果这个集合更大,我们就会从D继续。
此算法只会访问直接受删除或添加边缘影响的节点,因此(除了每个节点所需的额外存储空间外)应接近最佳状态。
答案 2 :(得分:1)
这是你的作业吗?
最简单的解决方案是从源节点开始在原始图上执行DFS(http://en.wikipedia.org/wiki/Depth-first_search)或BFS(http://en.wikipedia.org/wiki/Breadth-first_search)。这将为您提供所有原始点亮的节点。
现在删除有问题的边缘。再做一次DFS。您仍然可以保持点亮的节点。
输出出现在第一组但不是第二组的节点。
这是渐近最优算法,因为你做了两个DFS(或BFS),它们占用O(n + m)次和空间(其中n =节点数,m =边数),这决定了复杂性。您需要至少o(n + m)的时间和空间来读取输入,因此算法是最佳的。
现在,如果你想删除几个边缘,那将会很有趣。在这种情况下,我们将讨论动态数据结构。这是你的意图吗?
编辑:考虑到评论:
BFS的伪代码,用于搜索从任何起始节点可到达的所有节点:
Queue q = [all starting nodes] while (q not empty) { x = q.pop() forall (y neighbour of x) { if (y was not visited) { visited[y] = true q.push(y) } } }
用堆栈替换队列,你得到一种DFS。
答案 3 :(得分:0)
图表的大小和连接程度如何?您可以将源节点中的所有路径存储到所有其他节点,并查找节点,其中该节点的所有路径都包含一个删除边。
编辑:稍微扩展此说明
从每个源节点执行DFS。跟踪生成到每个节点的所有路径(作为边,而不是顶点,因此我们只需要知道所涉及的边,而不是它们的顺序,因此我们可以使用位图)。保持每个节点对从源到节点的路径数量的计数。
现在迭代路径。删除包含已删除边的任何路径,并减少该节点的计数器。如果节点计数器减少到零,则它被点亮,现在不是。
答案 4 :(得分:0)
在构建图形时,我会保留连接源节点的信息。(例如,如果边缘连接到源S1和S2,其源列表包含S1和S2)并创建具有以下信息的节点:输入边和输出边。删除边时,通过考虑节点的输入边来更新该边的目标节点的输出边。并使用DFS或BFS遍历更新边的所有目标节点。 (如果是循环图,请考虑标记)。在更新图形时,还可以找到没有任何具有源连接的边缘的节点(lit-> unlit节点)。但是,如果您想同时删除多个边缘,可能不是一个好的解决方案,因为这可能会导致一次又一次地遍历相同的边缘。