找到最短等待时间的路径

时间:2013-05-07 18:13:13

标签: java algorithm depth-first-search

我正在从竞争中解决这个问题。我将在这里简要描述这个问题。

厨师正试图在时间T之前到达会议,但他希望以最少的等候时间在巴士站进行。除非他在T之前到达目的地并且在巴士站等候最少,否则他不介意选择长路线。他从1号站开始,目的地是最后一站。这是输入规范......

N T M 
U V S E
U V S E
... and so on

其中N是站点数,T是会议时间,M是总线数。接下来的M行是公交车的详细信息。 U是公共汽车开始的地方,V是公共汽车到达的地方。 S是起始时间,E是到达时间。因此,总线在车站U开始,在时间S,并在时间E到达车站V.

Constraints
2 ≤ N ≤ 50000
1 ≤ T ≤ 109
1 ≤ M ≤ 100000 (105)
1 ≤ U ≤ N
1 ≤ V ≤ N
U ≠ V
0 ≤ S < E ≤ 10

这是我尝试过的,在代码之后和代码中进行了解释。

public int findMax(int nextStation, int rcd, int start, int end) {
    int tt = start - rcd;
    // If we reached destinaion, i.e the last station
    // no more wait has to be done and we return the time
    // required to reach here
    if (nextStation == noOfStations) {
        return tt;
    }

    // TODO : we already found a better path, so we skip this one
    // if (tt > minTillNow) {
    // return Integer.MAX_VALUE;
    // }

    List<Bus> buses = stations.get(nextStation);

    // If we have not reached finalStation
    // and there are no more buses from this station,
    // we reached a dead end.
    if (buses == null) {
        return -1;
    }

    int temp, min = Integer.MAX_VALUE;
    // If there are buses from this station, we try all
    // of them
    for (int i = 0; i < buses.size(); i++) {
        temp = findMax(buses.get(i).v, end, buses.get(i).s, buses.get(i).e);
        // Find minimum wait-time
        if (temp != -1 && temp < min) {
            min = temp;
        }
    }
    // If no subtree has a path
    if (min == Integer.MAX_VALUE) return -1;
    // if the wait to reach here is greater than any subsequent
    else if (min < tt) return tt;
    else
        return min;
}

我正在做一个DFS,从第一个站开始,沿着任何路径找到最大等待时间直到结束,然后选择沿这些路径的所有等待时间的最小值。这适用于给定的输入示例..

Input:
5 10 5
1 2 1 2
1 5 3 4
2 4 4 5
2 5 5 6
4 5 6 7

Output:
2 

但是当我提交一些测试输入时出现“错误答案”而失败。 有人可以通过上述方法发现问题吗?这也是一般的好方法吗?这会是什么复杂性?我认为它应该是M线性的,是正确的逼近。

2 个答案:

答案 0 :(得分:1)

我认为您忘记的是测试您是否仍然可以在for循环中捕获总线(如下面的示例所示)。

除此之外,我认为你的代码比需要的更复杂。首先,-1对“无路径”进行编码并不是很方便,因为在评估最短等待时间时需要额外的测试(我假设如果没有路径则必须返回-1,但你最终可以处理这个问题。)

我会提出以下功能(并为NT引入了新名称,但我认为它们足够有意义。)

public int minWaitingTime(int currentStop, int currentTime, int waitingTime) {
    if (currentStop == destination) {
        // reached the destination, return waitingTime if we met the deadline, 
        // or 'infinity' otherwise
        // NOTE: I assumed currentTime <= deadline is ok, maybe that should be <
        return currentTime <= deadline ? waitingTime : Integer.MAX_VALUE;
    } else {        
        List<Bus> buses = stations.get(currentStop);

        int min = Integer.MAX_VALUE;
        for (Bus bus : buses) {
            // test if we can still catch this bus
            if (bus.s <= currentTime) {
                // update minimum
                min = Math.min(min, 
                        minWaitingTime(bus.v, bus.e, 
                            waitingTime + (bus.s - currentTime));
            }
        }

        return min;
    }
}

您现在可以将其称为:

public int findMinWaitingTime() {
    int min = minWaitingTime(1, 0, 0);
    return min == Integer.MAX_VALUE ? -1 : min;
}
是的,我希望这是一场古老的比赛,我现在不是在写你的解决方案......

答案 1 :(得分:1)

这看起来像Google Code Jam问题。您可以在他们的网站上找到其他人所做的解决方案。

使用深度优先搜索的问题在于它具有几何上增加的复杂性。因此,例如,如果每个站有10个站点和10个连接,则有10 ^ 10个路径,这些路径是数十亿。这就像试图蛮力解决国际象棋。

这种问题可以通过动态编程解决(Code Jam喜欢DP问题)。你之所以知道这一点,是因为任何一个站点的最佳移动都与你之前的站点无关。从最后一站向后解决问题。您将始终能够以这种方式找到任何特定移动的最短等待时间。

唯一的障碍是最小等待时间路径可能会在T之后到达。

要解决此问题,您应该在最小等待路径上进行回溯搜索。换句话说,您像以前一样执行DP解决方案,但要记录花费的总时间。如果它超过T,则回溯到上一个节点并继续从那里搜索。


BTW避免使用像“temp”和“i”这样无意义的变量名,这会导致错误。