关于算法,我面临技术挑战。
假设我有这个日期和价格清单:
List<ReservationPrice> prices = new List<ReservationPrice>();
prices.Add(new ReservationPrice { NumberOfDays = 1, Price = 1000 });
prices.Add(new ReservationPrice { NumberOfDays = 2, Price = 1200 });
prices.Add(new ReservationPrice { NumberOfDays = 3, Price = 2500 });
prices.Add(new ReservationPrice { NumberOfDays = 4, Price = 3100 });
prices.Add(new ReservationPrice { NumberOfDays = 7, Price = 4000 });
我现在想做的是:
根据天数从列表中给出最优惠的价格。
因此,如果要求3天,列表中的最优价格来自孩子一(1000)和二(1200),但当然有一些不同的组合,你必须首先尝试。从这个列表中找到最优价格的算法怎么样?
谢谢!
答案 0 :(得分:0)
上面链接的wiki页面说这是一个完整的问题,所以我猜没有好办法解决它。 但是,如果你想暴力破解它,我建议先过滤掉“无用的”字段。
在您的示例中,通过一些简单的检查,您可以过滤掉3和4,因为它们总是可以覆盖1 + 2和2 + 2。 (你也可以用蛮力这样做)
然后,您应该只选择3个组合,如果您为租赁公司或酒店制作该计划,这不应该太糟糕......
(如果你想查看30天的最佳价格,它应该只需要最多30 x 15 x 4的操作,这对于计算机计算来说根本不是那么大。)
嗨WizardOfOdds:
我正在努力学习如何解决这个问题,如0-1背包,我很困惑......
(你可以简单地'种子'你的“0-1 背包“与'一天'一样多 你要找的最大值,一半 许多“两天”,三分之一 '三天'等。)。
如果我们想要找到解决方案7天,我们应该理解为:
7 x 1天 0/1?
3x 2天 0/1?
2x 3天 0/1?
1x 4天 0/1?
我想,我真的不明白/为什么是
尽可能多的“一天”,“一半”,“第三”......
答案 1 :(得分:0)
它类似于subset sum problem。
这是伪代码中的算法:
Let S[i] = minimum sum obtainable for days = i, initialized to infinite at first
S[0] = 0
for (int i = 0; i < prices.Count; ++i)
{
for (int j = MAX_DAYS; j >= prices[i].days; --j)
S[j] = min(S[j], S[j - prices[i].days] + prices[i].price);
}
然后使用S
回答每个查询。这是在C#中。当然还有改进的余地。
class Program
{
static void Main()
{
List<ReservationPrice> prices = new List<ReservationPrice>();
prices.Add(new ReservationPrice { NumberOfDays = 1, Price = 1000 });
prices.Add(new ReservationPrice { NumberOfDays = 2, Price = 1200 });
prices.Add(new ReservationPrice { NumberOfDays = 3, Price = 2500 });
prices.Add(new ReservationPrice { NumberOfDays = 4, Price = 3100 });
prices.Add(new ReservationPrice { NumberOfDays = 7, Price = 4000 });
DaysMinSum.Precompute(prices);
Console.WriteLine(DaysMinSum.GetAnswer(5));
Console.WriteLine(DaysMinSum.GetAnswer(4));
Console.WriteLine(DaysMinSum.GetAnswer(7));
Console.WriteLine(DaysMinSum.GetAnswer(6));
Console.WriteLine(DaysMinSum.GetAnswer(100));
Console.WriteLine(DaysMinSum.GetAnswer(3));
}
}
static class DaysMinSum
{
private static Dictionary<int, int> S = new Dictionary<int, int>();
public static int GetAnswer(int numDays)
{
if (S.ContainsKey(numDays))
{
return S[numDays];
}
else
{
return -1;
}
}
public static void Precompute(List<ReservationPrice> prices)
{
S.Clear();
int maxDays = 0;
for (int i = 0; i < prices.Count; ++i)
{
maxDays += prices[i].NumberOfDays;
}
for (int i = 0; i <= maxDays; ++i)
{
S.Add(i, 1 << 30);
}
S[0] = 0;
for (int i = 0; i < prices.Count; ++i)
{
for (int j = maxDays; j >= prices[i].NumberOfDays; --j)
{
S[j] = Math.Min(S[j], S[j - prices[i].NumberOfDays] + prices[i].Price);
}
}
}
}
class ReservationPrice
{
public int NumberOfDays { get; set; }
public int Price { get; set; }
}
答案 2 :(得分:0)
虽然这基本上是背包问题,但您可以做一些简单的分析来筛选出糟糕的决策(例如,3天和4天的预订套餐)。
首先,我会根据天数和每日平均价格对列表进行排序。在您的示例中,这将产生...
Days Average ---- ------- 1 1000 2 600 3 833 4 775 7 571
然后我会过滤掉遍历此列表时增加的所有值。一个简单的假设可能是,通过使用X短期住宿的总和,从较短停留时间平均增加的一天可以有更好的利率(显然不是所有时间都是真的 - 设置1天费率1301和3天速率变得更好,但4天的速度仍然很糟糕 - 尽管它在你的示例中有效。更详细的分析将其转化为背包问题。
Days Average ---- ------- 1 1000 2 600 3 833 removed 4 775 removed 7 571
现在,在建立预订时,按照预期总天数的下降天数排序,从预期的天数中减去最大可能的预留,直到您填写预订。因此,为期11天的预订将是7天和2天2天; 10天是7天,2天,1天。