如何将数字转换为一系列价格

时间:2010-04-21 15:24:15

标签: c# linq algorithm range integer

我想计算在购买我的产品许可证时向客户收取的金额。

我在许可范围内出售它:

  • 1-10:$ 50 / user
  • 11-20:40美元/用户
  • 21-30:$ 30 / user
  • 31-50:$ 20 / user

所以当有人购买136张牌照时,我会向他收费:

50 x 2 x $20 = $2000
30 x 1 x $30 = $900
     6 x $50 = $300

我正在寻找一种关于如何处理给定数字并将其分解为范围内出现次数的算法。 我怎样才能在普通的C#或LINQ中做到这一点?

------------ EDIT ----------------------------

我开始了一个不那么混乱的问题(Algorithm for Fogbugz pricing scheme),我得到了我一直在寻找的答案。

谢谢大家..

5 个答案:

答案 0 :(得分:2)

如果提供这种价格结构,我认为通过购买最适合他们需要的包装来降低成本符合客户的最佳利益。以下算法使用动态编程来计算最小可能的价格以准确购买一定数量的许可证(您可以通过购买超过您需要的金额来节省资金,但我还没有实现):

int getPrice(int n)
{
    if (n >= 1 && n <= 10) return 50 * n;
    if (n >= 11 && n <= 20) return 40 * n;
    if (n >= 21 && n <= 30) return 30 * n;
    if (n >= 31 && n <= 50) return 20 * n;
    throw new Exception("Impossible");
}

int minimizePrice(int n)
{
    int[] minimumPrice = new int[n + 1];
    for (int i = 1; i <= n; ++i)
    {
        minimumPrice[i] = int.MaxValue;
        for (int j = Math.Max(0, i - 50); j < i; ++j)
        {
            minimumPrice[i] = Math.Min(minimumPrice[i],
                minimumPrice[j] + getPrice(i - j));
        }
    }
    return minimumPrice[n];
}

对于70个许可证,最低价格是1400美元,可以通过购买2个35个许可证块来获得。你建议使用贪心算法。这会让您的客户感到困惑。一个聪明的客户将下两个订单而不是一个大订单,节省400美元。

我建议您更改价格,以便每个20美元可以购买的许可证数量没有上限。

答案 1 :(得分:0)

这看起来非常类似于对购买进行更改的算法(选择哪个硬币)。唯一的区别是你要与范围而不是单个数字进行比较。

代码看起来像这样:

var val = 136;
var price = 0;
while (val > 0) 
{
  var range = FindMatchingRange(val); // Use a dictionary, list, or array.
  var number = Math.Min(val, range.Max);
  price += range.CostPerUser * number;
  val -= number;
}

答案 2 :(得分:0)

如果我是需要10个许可证的人,根据您建议的定价计划,我为什么只购买10个许可证?

10个许可证* 50美元/许可证= 500美元

11个许可证* 40美元/许可证= 440美元

您想要的是降低最近购买的许可证的成本的计划。因此,对于想要11个许可证的人,他们会支付:

(10个许可证* 50美元/许可证)+(1个许可证* 40美元/许可证)= 540美元

可能的计划如下:

first 10 licenses (1-10): $50/user
next 10 licenses (11-20): $40/user
next 10 licenses (21-30): $30/user
all licenses after that (31+) : $20/user

编写代码来计算任意数量用户的最终成本是一项简单的练习。购买136个许可证的人的计算结果如下:

(10个许可证* 50美元/许可证)+(10个许可证* 40美元/许可证)+(10个许可证* 30美元/许可证)+(106个许可证* 20美元/许可证)= 500美元+ 400美元+ 300美元+ 2120美元= 3,220美元。< / p>

在我看来,原来的定价计划很古怪。以去年购买了130个许可证的客户为例,他们需要再购买10个许可证。为他们收取最高费率的理由是什么?他们是一个大批量的客户,你想以最低的“边际”价格出售他们(并且他们有理由期望获得)额外的许可证。

答案 3 :(得分:0)

我为你做了一个计算课......更加以客户为导向。 它使用您定义的价格范围计算最便宜的价格。

示例:136个许可证

50个许可证每个20美元(因为:31-50:20美元/用户)

50个许可证每个20美元(因为:31-50:20美元/用户)

36个许可证每个20美元(因为:31-50:20美元/用户)

总计:1720


示例130许可证

50个许可证每个20美元

50个许可证每个20美元

30个许可证30美元每个

总计:1900


课程代码:

   public class PriceCalculator
    {
        public List<OrderPackage> CalculateCheapestPrice(Int32 AmountOfLicenses, 
            List<PriceRange> PriceRanges, out Double Total)
        {
            List<OrderPackage> result = new List<OrderPackage>();
            Total = 0;

            Int32 AmountsOfLicensesleft = AmountOfLicenses;

            PriceRanges.Sort(ComparePrice);

            for (int i = 0; i < PriceRanges.Count; i++)
            {
                for (int j = PriceRanges[i].MaxAmount; j >= PriceRanges[i].MinAmount; j--)
                {
                    if (j <= AmountsOfLicensesleft)
                    {
                        OrderPackage Order = new OrderPackage();
                        Int32 AmountOfThisPackage = AmountsOfLicensesleft / j;
                        //Int32 AmountForThisPrice = Convert.ToInt32(Math.Floor(tmp));

                        Order.PriceRange = PriceRanges[i];
                        Order.AmountOfLicenses = j;

                        Total += Order.AmountOfLicenses * Order.PriceRange.PricePerLicense;

                        for (int k = 0; k < AmountOfThisPackage; k++)
                        {
                            result.Add(Order);
                        }

                        AmountsOfLicensesleft = AmountsOfLicensesleft - (AmountOfThisPackage * j);
                    }
                }
            }

            return result;
        }

        private static int ComparePrice(PriceRange x, PriceRange y)
        {
            if (x.PricePerLicense == y.PricePerLicense)
                return 0;

            if (x.PricePerLicense > y.PricePerLicense)
                return 1;

            if (x.PricePerLicense < y.PricePerLicense)
                return -1;

            return 0;
        }

        public class OrderPackage
        {
            public PriceRange PriceRange { get; set; }
            public Int32 AmountOfLicenses { get; set; }
        }

        public class PriceRange
        {
            public int MinAmount { get; set; }
            public int MaxAmount { get; set; }

            public Double PricePerLicense { get; set; }
        }
    }

用法示例:

private void button1_Click(object sender, EventArgs e)
{
    // Preparing PriceRangeDefinitions
    List<PriceCalculator.PriceRange> PriceRangeDefinitions = new List<PriceCalculator.PriceRange>();
    PriceRangeDefinitions.Add(new PriceCalculator.PriceRange() { MinAmount = 1, MaxAmount = 10, PricePerLicense = 50 });
    PriceRangeDefinitions.Add(new PriceCalculator.PriceRange() { MinAmount = 11, MaxAmount = 20, PricePerLicense = 40 });
    PriceRangeDefinitions.Add(new PriceCalculator.PriceRange() { MinAmount = 21, MaxAmount = 30, PricePerLicense = 30 });
    PriceRangeDefinitions.Add(new PriceCalculator.PriceRange() { MinAmount = 31, MaxAmount = 50, PricePerLicense = 20 });

    // Start the Calculation
    PriceCalculator calculator = new PriceCalculator();
    Double Total;
    List<PriceCalculator.OrderPackage> Packages =
        calculator.CalculateCheapestPrice(130, PriceRangeDefinitions, out Total);

    // Show Proof of Concept
    String ProofOfConcept = String.Empty;
    for (int i = 0; i < Packages.Count; i++)
    {
        ProofOfConcept += Packages[i].AmountOfLicenses.ToString() + " Licenses " +
            Packages[i].PriceRange.PricePerLicense.ToString() + "$ each" + Environment.NewLine;
    }
    ProofOfConcept += Environment.NewLine + "TOTAL: " + Total.ToString();

    MessageBox.Show(ProofOfConcept);
}

答案 4 :(得分:-1)

KeyValuePair集合或字典可能吗?