查找X天数最便宜的价格

时间:2010-05-03 12:52:45

标签: c# .net algorithm

关于算法,我面临技术挑战。

假设我有这个日期和价格清单:

        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),但当然有一些不同的组合,你必须首先尝试。从这个列表中找到最优价格的算法怎么样?

谢谢!

3 个答案:

答案 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天。