【发布时间】:2012-02-27 06:11:48
【问题描述】:
有一个火车站,我们有它的交通信息,它就像(到达,离开)时间对访问车站的火车。像这样的东西 T{ [1,5],[2,4],[5,9],[3,10] }。然后如何找到管理此流量所需的最少平台数。
【问题讨论】:
-
这是作业吗?然后你应该这样标记它。
标签: c algorithm optimization data-structures
有一个火车站,我们有它的交通信息,它就像(到达,离开)时间对访问车站的火车。像这样的东西 T{ [1,5],[2,4],[5,9],[3,10] }。然后如何找到管理此流量所需的最少平台数。
【问题讨论】:
标签: c algorithm optimization data-structures
您需要找出最大重叠,对吗?这将为您提供最少数量的平台。只需使用等于 0 的 max(times) 元素初始化一个数组,然后添加然后迭代每个 (arrival, departure) 区间,将区间中的每个数组元素加 1。
那么数组中任何元素的最大值就是您需要的最小平台数。这适用于整数值间隔。不过,数组可能不是最快的方法。我会把它留给你。
【讨论】:
有一个时间为 O(n log n) 的解,其中 n 是给定的时间对数。 你必须回答这个问题:有多少辆火车同时站在车站? 为此,我们首先“标准化”时间值:确定所有可能发生有趣事情的时间段。为此,对给定的所有到达和离开时间进行排序并消除重复。
在 T = {[1,5], [2,4], [5,9], [3,10]} 的示例中,这会产生一个数组 A,时间点为 [1,2,3,4,5,9,10],大小 m = 7。
现在我们将每对的到达和离开时间转换为火车占用车站的时间段,即。 e.我们在数组 A 中找到时间值的索引(通过二进制搜索)。例如。对于 [3, 10],我们得到索引 2 和 6,从零开始计数。
这就是简单的部分。使用索引对时间值进行排序和匹配每个都在 O(n log n) 中运行。现在我们要计算每个指标,当时有多少辆火车停在车站。为了有效地做到这一点,我们使用了分段树。
本网站介绍了如何使用段树: http://community.topcoder.com/tc?module=Static&d1=tutorials&d2=lowestCommonAncestor#Segment_Trees
在下文中,您将找到 C++ 中的实现。我希望你能适应你的需要。如果还有任何问题,请随时提问。
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
/** Given a number n and n pairs of arrival and departure times of trains,
* this program calculates the number of platforms needed in time O(n log n)
* If a train arrives exactly when another one leaves the station, you need
* two platforms. */
int main () {
int n;
cin >> n;
vector< pair<int,int> > T(n);
vector< int > A(2*n);
for (int i = 0; i < n; ++i) {
int arrival, departure;
cin >> arrival >> departure;
A[2*i] = arrival;
A[2*i+1] = departure;
T[i] = pair<int,int>(arrival, departure);
}
sort(A.begin(), A.end());
int m = unique(A.begin(), A.end()) - A.begin();
// for easy indexing, we need m to be a potency of 2
int pot2m = 1; while (pot2m < m) pot2m *= 2;
// Elements pot2m ... pot2m + m represent the bottom layer of the segment tree
vector< int > segtree(2*pot2m+1, 0);
// Now let's add everything up
for (int i = 0; i < n; ++i) {
int arrival = find(A.begin(), A.end(), T[i].first) - A.begin();
int departure = find(A.begin(), A.end(), T[i].second) - A.begin();
// Now increment
int a = arrival + pot2m;
int b = departure + pot2m + 1;
while (a < b) {
if (a % 2 == 1) ++segtree[a];
if (b % 2 == 1) ++segtree[b-1];
a = (a+1) / 2;
b = b / 2;
}
}
// Find the maximum value in the cells
int a = pot2m;
int b = pot2m + m;
while (a < b) {
int i, j;
for (i = a/2, j = a; j < b-1; ++i, j+=2) {
segtree[i] += max(segtree[j], segtree[j+1]);
}
if (j == b-1) segtree[i] += segtree[j]; // To handle odd borders
a /= 2;
b /= 2;
}
cout << "You need " << segtree[1] << " platforms." << endl;
return 0;
}
【讨论】:
我会回答你的主题行问题“如何解决这些问题以及哪种数据结构更好处理?”
您已经为上述内容提供了一个示例。这类问题称为优化问题 (http://en.wikipedia.org/wiki/Optimization_problem)。
数据结构的选择将基于空间/时间的权衡。因此,例如,可以通过使用简单的数组或哈希表或图形来解决上述问题。真正重要的是,有时解决此类问题可能需要指数级的运行时间,这可能会使它们成为 NP-Complete/Hard。假设考虑到您的示例,您有 n 个平台和 m 个火车(其中 n 和 m 非常大),那么就有可能发生组合爆炸。
另外,如果它导致指数时间并且说是一个 NP-Complete/Hard 问题,那么也有几种启发式算法(例如,可以使用 Ant Colony Optimization 解决旅行推销员问题)来解决它,也许不是最理想的。
在这种情况下,算法比数据结构更重要。
【讨论】:
创建一个这样的结构数组:(Time, IsArrival),其中 IsArrival = +1 表示到达或 -1 表示离开
按时间键排序(考虑时间相等的情况)
初始化 PlatformsNeeded = 0
遍历排序数组,将 IsArrival 添加到 PlatformsNeeded,记住最大值
【讨论】: