我正在开展一个小项目,根据用户的一些意见,我需要帮助找到最好和最便宜的门票:
有x张票。门票可以包括:
我想我正在寻找某种算法来确定基于期间(包括或不包括跳过日期)的最佳票证组合,以及它们的价格。
另外,我想有必要考虑这样一种情况,即购买一张比我实际需要更多天票的期票会更好,更便宜,但根据我骑多少次票价会更便宜每天都要去......
更新(基于Petr建议..)
<?php
$tickets = array(
array("price"=>5, "label"=>"single", "period"=>null),
array("price"=>10, "label"=>"1 day", "period"=>1),
array("price"=>30, "label"=>"3 days", "period"=>3),
array("price"=>45, "label"=>"7 days", "period"=>7)
);
$trips = 2;
$startDate = new DateTime("2015-06-23");
$endDate = new DateTime("2015-06-30");
$endDate->modify("+1 day");
$interval = DateInterval::createFromDateString('1 day');
$period = new DatePeriod($startDate, $interval, $endDate);
$cost = array();
$day = 1;
foreach( $period as $date ){
$span = $startDate->diff($date);
$days = ( $span->format('%a') + 1 );
$ticket = getCheapestTicket( $days );
$cost[ $day ] = $ticket;
$day++;
}
function getCheapestTicket( $days ){
global $tickets, $trips;
$lowestSum = null;
$cheapestTicket = null;
echo "-- getCheapestTicket --" . PHP_EOL;
echo "DAYS TO COVER: " . $days . " / TRIPS: " . $trips . PHP_EOL;
foreach( $tickets as $ticket ){
$price = $ticket['price'];
$period = $ticket['period'] ? $ticket['period'] : -1;
if( $ticket['period'] ){
$units = ceil( $days / $period );
$sum = round( $units * $price );
}else{
$units = ceil( $days * $trips );
$sum = round( ( $days * $price ) * $trips );
}
if( $sum <= $lowestSum || !$lowestSum ){
if( $ticket['period'] > $cheapestTicket['period'] ){
$cheapestTicket = $ticket;
$lowestSum = $sum;
}else{
$lowestSum = $sum;
$cheapestTicket = $ticket;
}
}
echo "TICKET: " . $ticket['label'] . " / Units to cover days: " . $units . " / Sum: " . $sum . " / Period: " . $period . PHP_EOL;
}
echo "CHEAPEST TICKET: " . $cheapestTicket['label'] .
" / PRICE PER UNIT: " . $cheapestTicket['price'] . " / SUM: " . $lowestSum . PHP_EOL. PHP_EOL;
return $cheapestTicket;
}
我不确定这是否还在路上:))
答案 0 :(得分:0)
假设您已将所有数据存储在某些天数中,并且每天都记录当天的游乐设施数量。
旁注:我将放宽持续<24小时的票价条件,并假设每张期刊票都适合日期(即,不是从15:00开始,持续到第二天的14:59)。这可以通过将其视为每小时时间单位而不是天数来解决。
次优解:
现在让我们分配当天购买一张车票的成本,然后开始迭代阵列并检查你是否可以用更便宜的机票替换其中一些。完成后不做任何更改。这里的问题是你可能会错过最佳解决方案。您可以分配两张3天票(第1-3天和第7-9天),其中7天票(2-8张)和2张1天票更好。
树解决方案:(叶子中的数据)
树选项是将其排列在树中,每个子树保存该子树的最佳解决方案。然后,每个子树根可以检查是否使用票据&#34;覆盖&#34;当考虑到遗漏部分的根的值时,只有部分子树才有用
也许排名树会在这里派上用场。
答案 1 :(得分:0)
您可以使用动态编程方法解决此问题。
首先,为了简化算法,让每个l
计算最便宜的单票据,可用于连续l
天。{对于你的例子,这将是:1天10美元,2天30美元(购买3天票,仅使用2天),3天30美元,4-7天45美元等(显然会有一些最大价值除l
之外不会有这样的票。)将这些结果表示为cost[l]
。
现在主要的动态编程解决方案。对于[i
,begin
]范围内的每个日期end
,请计算ans[i]
=购买门票的最低费用,以至少覆盖从begin
到i
的间隔i
。
假设您已经在日期i
之前计算了所有值,则日期i
的计算很简单。您将需要一些在l
天结束的票证。假设它涵盖cost[l]
天的长度,那么此最后一张票的价格将为begin
,您还必须涵盖从i-l
到ans[i-l]
的天数,这将花费i-l
(如果begin
在i
之前,则为零。)因此,对于所有可能l
的给定O(NL)
迭代,找到最小化解决方案的那个。
这为您提供了N
解决方案,其中L
是天数,{{1}}是单个故障单的最大范围。
这都假定每个勾选的内容涵盖几个完整的连续天。如果它涵盖了24个整个小时(从购买时到第二天的同一小时),那么只需计算每小时的答案。
答案 2 :(得分:0)
从我的例子来看,基于@Petr所说的,我真的不知道如何解决这种情况,例如期限为8天(每天2次旅行),你最终会得到一个结果像这样:
-- getCheapestTicket --
DAYS TO COVER: 8 / TRIPS: 2
TICKET: single / Units to cover days: 16 / Sum: 80 / Period: -1
TICKET: 1 day / Units to cover days: 8 / Sum: 80 / Period: 1
TICKET: 3 days / Units to cover days: 3 / Sum: 90 / Period: 3
TICKET: 7 days / Units to cover days: 2 / Sum: 90 / Period: 7
CHEAPEST TICKET: 1 day / PRICE PER UNIT: 10 / SUM: 80
它应该给我这个组合的结果:
7 days, $45
1 day, $10
或者这就是你说的时候的意思&#34;(显然会有一些超过l的最大价值,没有这样的票。)&#34;?
对你的想法进行另一轮解释真是太好了!