Algorithm 列车行程分组算法
想象你有一个完整的日历年在你面前。在某些情况下,您可能会在一天内乘坐几次火车,并且每次旅行可能会到达不同的地点(即,您为每次旅行支付的车票金额可能不同) 因此,您将获得如下数据:Algorithm 列车行程分组算法,algorithm,Algorithm,想象你有一个完整的日历年在你面前。在某些情况下,您可能会在一天内乘坐几次火车,并且每次旅行可能会到达不同的地点(即,您为每次旅行支付的车票金额可能不同) 因此,您将获得如下数据: Date: 2018-01-01, Amount: $5 Date: 2018-01-01, Amount: $6 Date: 2018-01-04, Amount: $2 Date: 2018-01-06, Amount: $4 ... 现在,您必须将这些数据分组到存储桶中。一个存储桶最多可跨越31个连续日(无间隔
Date: 2018-01-01, Amount: $5
Date: 2018-01-01, Amount: $6
Date: 2018-01-04, Amount: $2
Date: 2018-01-06, Amount: $4
...
现在,您必须将这些数据分组到存储桶中。一个存储桶最多可跨越31个连续日(无间隔),且不能与另一个存储桶重叠
如果铲斗的列车行程少于32次,则铲斗将为蓝色。如果它有32次或更多的火车旅行,它将是红色的。这些桶还将根据票证成本的总和获得一个值
当你把所有的旅行分组后,蓝色的桶就会被扔掉。所有红色水桶的价值加起来,我们称之为奖品
目标是获得最高价值的奖品
这就是我的问题。我想不出一个好的算法来做这件事。如果有人知道解决这个问题的好方法,我愿意听听。或者,如果您知道其他任何地方可以帮助设计这样的算法。简化挑战,但不要太多,以制作一个可以忽略的示例,可以手动解决 这有助于找到正确的问题 例如,只需10天,桶的最大长度为3: 对于构建桶并为其着色,我们只需要票证计数,这里是0、1、2、3 平均来说,我们每天需要超过一个桶,例如2-0-2是3天4张票。或者1-1-3,1-3,1-3-1,3-1-2,1-2 但我们只能选择2个红色桶:2-0-2和(1-1-3或1-3-3或3-1-2),因为1-2最终只有3张票,但我们至少需要4张(比每个桶的最大日跨度多一张票) 但是,虽然3-1-2明显比1-1-3多,但少票的价值可能更高
蓝色区域是不太有趣的区域,因为它不会根据票数自动进站。这可以通过动态规划来解决 首先,按日期排序记录,并按顺序排序。 让
天(1)
,天(2)
,…,天(n)
成为购票的日子。
让成本(1)
,成本(2)
,…,成本(n)
分别为门票成本
让<代码>乐趣(K)< /代码>如果我们只考虑第一个代码> k>代码>记录,将是最好的奖励。 我们的动态规划解决方案将计算
fun(0)
,fun(1)
,fun(2)
,…,fun(n-1)
,fun)
,使用前面的值来计算下一个值
基础:
fun(0)=0
转换:
什么是最佳的解决方案,<代码>乐趣(K)< /代码>,如果我们只考虑第一个<代码> k< /代码>记录?
有两种可能性:要么删除k
-th记录,然后解决方案与fun(k-1)
相同,要么k
-th记录是存储桶的最后一条记录。
让我们考虑在循环中用<代码> k< /代码>记录结束的所有可能的桶,如下所述。
查看记录k
,k-1
,k-2
,…,直到第一条记录。
让当前索引为i
。
如果从i
到k
的记录跨度超过31
连续天,则中断循环。
否则,如果记录数k-i+1
至少为32
,我们可以解决子问题fun(i-1)
,然后将i
中的记录添加到k
,获得cost(i)+cost(i+1)+…+成本(k)
。
值fun(k)
是这些可能性中的最大值,以及删除k
-th记录的可能性
回答:这只是fun(n)
,我们考虑了所有记录的情况
在伪代码中:
fun[0] = 0
for k = 1, 2, ..., n:
fun[k] = fun[k-1]
cost_i_to_k = 0
for i = k, k-1, ..., 1:
if day[k] - day[i] > 31:
break
cost_i_to_k += cost[i]
if k-i+1 >= 32:
fun[k] = max (fun[k], fun[i-1] + cost_i_to_k)
return fun[n]
fun[0] = 0
for k = 1, 2, ..., n:
fun[k] = fun[k-1]
cost_i_to_k = 0
quantity_i_to_k = 0
for i = k, k-1, ..., 1:
if k-i+1 > 31:
break
cost_i_to_k += cost[i]
quantity_i_to_k += quantity[i]
if quantity_i_to_k >= 32:
fun[k] = max (fun[k], fun[i-1] + cost_i_to_k)
return fun[n]
目前还不清楚是否允许我们将一天的记录拆分为不同的存储桶。 如果答案是否定的,我们将不得不强制执行它,不考虑在一天内开始或结束记录之间的桶。 从技术上讲,它可以通过几个
if
语句来完成。
另一种方法是考虑“天”而不是“记录”,而不是“<代码>日期>代码>和<代码>费用> >,我们将工作几天。
每天将有成本
,当天的总门票成本,以及数量
,门票数量
编辑:根据评论,我们确实不能分割任何一天。 然后,在进行一些预处理以获取天数记录而不是票证记录之后,我们可以按如下方式进行操作,使用伪代码:
fun[0] = 0
for k = 1, 2, ..., n:
fun[k] = fun[k-1]
cost_i_to_k = 0
for i = k, k-1, ..., 1:
if day[k] - day[i] > 31:
break
cost_i_to_k += cost[i]
if k-i+1 >= 32:
fun[k] = max (fun[k], fun[i-1] + cost_i_to_k)
return fun[n]
fun[0] = 0
for k = 1, 2, ..., n:
fun[k] = fun[k-1]
cost_i_to_k = 0
quantity_i_to_k = 0
for i = k, k-1, ..., 1:
if k-i+1 > 31:
break
cost_i_to_k += cost[i]
quantity_i_to_k += quantity[i]
if quantity_i_to_k >= 32:
fun[k] = max (fun[k], fun[i-1] + cost_i_to_k)
return fun[n]
这里,i
和k
是天数。
请注意,我们考虑范围内的所有可能的日期:如果没有特定日期的票,我们只使用零值作为其<代码>成本<代码>和<代码>数量< /代码>值。
Edit2: 上面允许我们计算最大的总奖金,但是我们到达那里的桶的实际配置如何呢? 一般的方法是回溯:在位置
k
,我们想知道我们是如何得到fun(k)
,如果最佳方法是跳过k
-第条记录,或者从k
到i-1
,因为i
方程fun[k]=fun[i-1]+成本对成本
有效。
我们继续,直到i
降至零
两种常用的实现方法之一是存储par(k)
,一个“父级”,以及fun(k)
,它对我们如何获得最大值进行编码。
例如,如果par(k)=-1
,则最优解跳过k
-条记录。
否则,我们将最优索引i
存储在par(k)
中,因此