面试:找到几个元素的最短路径

发布于 2024-09-11 03:12:17 字数 117 浏览 1 评论 0原文

有一个博物馆,组织为 NxN 房间。部分房间已上锁且无法进入。其他房间是开放的,部分房间有警卫。警卫只能在博物馆内向北、南、东、西移动,只能穿过开放的房间。对于每个房间,找到到守卫的最短距离。你的算法的时间复杂度是多少?

There is a museum organized as NxN room. Some rooms are locked and inaccessible. Other rooms are open and some rooms have guards. Guards can only move north, south, east and west, only through open rooms and only within the museum. For each room, find the shortest distance to a guard. What is the time complexity of your algorithm?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

杀手六號 2024-09-18 03:12:17

首先,考虑一种相对简单的方法。

将每个警卫 G 作为房间集合中的顶点,R=N*N,以及相邻房间(边)之间的可能路径 E。

如果必须知道所有房间的最小距离,则从每个警卫到每个房间的 BFS。

这应该需要时间 G * (R+E),或类似 G*(N*N+E)G*(N*N)

这当然可以通过记忆来优化,因为每个 BFS 都会重复计算已经完成的子树。根据房间配置,这可以大大降低上述时间复杂度的 G。然而,我确信一定有比这更好的东西。

As a start, consider a relatively naive approach.

With each guard G as a vertex in the set of rooms, R=N*N, and possible paths between adjacent rooms (edges) E.

If all room minimum distances must be known, BFS from each guard to each room.

This should take time G * (R+E), or something like G*(N*N+E), or G*(N*N).

This can certainly be optimized with memoization, as each BFS will be computing subtrees repeatedly that have already been completed. Depending on the room configuration, this could greatly reduce G from the above time complexity. I'm sure there must be something better than this, however.

海未深 2024-09-18 03:12:17

图形化解决方案
每个房间都是一个节点
仅门打开的房间之间有边缘
使用Floyd–Warshall算法,然后检查每个房间和每个警卫之间的最小距离

房间数量 - R = N^2

警卫数量 - G

时间复杂度为 O(R^3 +R*G)= O( R^3) = O(N^6)

R^3 对于 Floyd–Warshall

Graphical solution
Each room is a node
There are edges only between rooms where the door is open
use the Floyd–Warshall algorithm and then to check the min distance between each room and each guard

number of rooms - R = N^2

number of guards - G

the time complexity is O(R^3 +R*G)= O(R^3) = O(N^6)

R^3 for Floyd–Warshall

花落人断肠 2024-09-18 03:12:17

如果我们使用人工源和从源到每个警卫的零长度边来增强博物馆图,则单源最短路径树可通过 BFS(未加权)/Dijkstra(加权)及时计算 Õ(n 2 + g),给出从每个房间到最近的警卫的距离。

If we augment the museum graph with an artificial source and zero-length edges from the source to each guard, then the single-source shortest paths tree, computable via BFS (unweighted)/Dijkstra (weighted) in time Õ(n2 + g), gives the distance from each room to the nearest guard.

離殇 2024-09-18 03:12:17

以下是 IVladthrotawayacct 提到的最佳解决方案 (O(N^2)) 的摘要。由于某种原因,他们的声音没有被听到:)

将 NxN 网格视为一个图,其中节点代表房间,边缘代表相邻房间之间的门。所有边的权重均为 1。一组节点 U 被标记为“受保护的房间”。

这个想法是使用 BFS 遍历,从连接到所有受保护房间的新节点开始,并从 v0 开始按距离递增的顺序扫描房间。每次访问一个节点时,到达该节点所采取的步数代表了距守卫房间的距离,并且由于路径扩展顺序,保证其最小:

Add an artificial node v0 and connect it to all nodes in U
Create a simple queue Q, that stores pairs <node, dist>
Q.enqueue(<v0, -1>) 
Create a hash set S, that contains all visited nodes
S.add(v0)
while not Q.isEmpty() {
    pathTail := Q.dequeue()
    output distance pathTail.dist for node pathTail.node
    for all neighbours v of pathTail.node
        if not S.contains(v)
            Q.add(<v, pathTail.dist + 1>)

    S.add(pathTail.node)

}

复杂性分析

该图是平面的,所以我们有 |V|+|E|=O(|V|)。因此,这个 BFS 运行时间为 O(|V|)=O(N^2)。

事实上,我们对边的权重是统一的,这让事情变得简单;队列保证具有单调的距离值。以 dijkstra 为例,边的权重可能不同,因此需要优先级队列,这会影响时间复杂度。这里提出的相同问题,如果房间之间的权重不同,则需要 O(NNlog N) 时间。

Here is a summary of the optimal solution (O(N^2)), mentioned by IVlad and throwawayacct. For some reason their voice is not heard :)

Consider the NxN grid as a graph with nodes representing rooms and edges representing doors between adjacent rooms. All edges have weight 1. A set of nodes U are marked as "guarded rooms".

The idea is to use a BFS traversal, that starts from a new node connected to all guarded rooms, and scans the rooms in increasing distance order from v0. Each time a node is visited, the number of steps that have been made for reaching it represents the distance from a guarded room, and it is guaranteed to be minimal due to the path expansion order:

Add an artificial node v0 and connect it to all nodes in U
Create a simple queue Q, that stores pairs <node, dist>
Q.enqueue(<v0, -1>) 
Create a hash set S, that contains all visited nodes
S.add(v0)
while not Q.isEmpty() {
    pathTail := Q.dequeue()
    output distance pathTail.dist for node pathTail.node
    for all neighbours v of pathTail.node
        if not S.contains(v)
            Q.add(<v, pathTail.dist + 1>)

    S.add(pathTail.node)

}

Complexity analysis

Note that the graph is planar, so we have |V|+|E|=O(|V|). Therefore, this BFS runs in O(|V|)=O(N^2) time.

The fact that we have a uniform weight for edges makes things simple; the queue is guaranteed to have monotonous distance values. With dijkstra for example, the edges can differ in their weight so a priority queue is needed, and this affects the time complexity. The same problem presented here, with varying weights between rooms would have required O(NNlog N) time.

沉鱼一梦 2024-09-18 03:12:17

您只需将该博物馆视为一张图并使用 Dijikstra 算法即可。

wiki 链接

您对给定页面上的复杂性进行了讨论。

You just need to look at that museum as one graph and use the Dijikstra algorithm.

wiki link

You have a discussion about complexity on the given page.

三岁铭 2024-09-18 03:12:17

您可以在本系列文章中找到 Dijkstra 的最短路径算法:

广度和深度优先搜索

You can find Dijkstra's shortest path algorithm implemented in this series of posts:

Breadth and depth first search

把昨日还给我 2024-09-18 03:12:17

拥有一个队列,其中每个条目都保存一个正方形的地址和一个整数。将所有守卫的位置放入一个队列中,每个守卫都用整数“0”标记。每个方格都应该有容纳数字的空间,并且它们最初都应该是空白的。

然后,只要队列中有东西,就从队列中拉出一个条目,并检查相关方格是否有标记值。如果是这样,则忽略该队列条目并继续下一个队列条目。否则,用队列中的值标记该方格,并将所有可直接到达的相邻方格放入队列中,其值比当前条目的值高一个(因此,当从队列中拉出第一批方格中的每一个时,他们会得到值“1”)。每个方格在为空时只会被访问一次,并且每个被访问的方格最多会导致另外四个方格排队,因此经过队列的物品总数将是方格数量的四倍加上警卫数量。通过在将每个方块添加到队列之前检查它是否为空,可以轻松地将这个值减少一个常数因子;这不会消除所有冗余队列,但会消除一些。

Have a queue whose entries each hold the address of one square along with an integer. Put the locations of all the guards in a queue, each tagged with the integer "0". Every square should have room for a number, and they should all be initially blank.

Then, as long as there's something in the queue, pull an entry out of a queue and check whether the square in question has a marked value. If so, just ignore that queue entry and proceed to the next one. Otherwise, mark the square with the value from the queue and put all directly-reachable neighboring squares in the queue with a value one higher than that of the present present entry (so as each of the first batch of squares is pulled from the queue, they'll get the value "1"). Each square will only be visited once when it's blank, and each visited square will result in at most four more squares being queued, so the total number of items going through the queue will be four times the number of squares, plus the number of guards. This value could easily be reduced by a constant factor by checking each square to see if it's blank before adding it to the queue; this would not eliminate all redundant queueing, but would eliminate some.

紫南 2024-09-18 03:12:17

我假设一个函数 edgeCost(i,j) 返回从房间 i 到房间 j 的转换成本(如果没有则无穷大,否则为 1)。另外,edgeCost(i,i) = 0 并且不存在负循环。设 R 为房间数(在您的情况下,R = N^2):

int path[R][R];
/*
 * Each path[i][j] is initialized to
 * edgeCost(i,j) or infinity if there is no 
 * edge between i and j.
 */

function play():
 for k = 1 to R:
  for i = 1 to R:
   for j = 1 to R:
    path[i][j] = min(path[i][j], path[i][k] + path[k][j]);

或者您可能知道,Floyd-Warshall 算法(所有对最短路径),时间复杂度为 O(|R|^3)。

I assume a function edgeCost(i,j) which returns the cost of the transition from room i to room j (infinite if there is none, 1 otherwise). Also edgeCost(i,i) = 0 and there are no negative cycles. Let R be the number of rooms (R = N^2 in your case):

int path[R][R];
/*
 * Each path[i][j] is initialized to
 * edgeCost(i,j) or infinity if there is no 
 * edge between i and j.
 */

function play():
 for k = 1 to R:
  for i = 1 to R:
   for j = 1 to R:
    path[i][j] = min(path[i][j], path[i][k] + path[k][j]);

Or as you may know it, the Floyd-Warshall algorithm (all pairs shortest paths), with O(|R|^3) time complexity.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文