Как конвертировать число в диапазон цен - PullRequest
3 голосов
/ 21 апреля 2010

Я хочу рассчитать сумму, которая будет взиматься с моих клиентов, когда они покупают лицензии на мой продукт.

Продаю в диапазонах лицензий:

  • 1-10: 50 долларов США / пользователь
  • 11-20: 40 долларов США / пользователь
  • 21-30: $ 30 / пользователь
  • 31-50: 20 долларов США / пользователь

Поэтому, когда кто-то покупает 136 лицензий, я буду взимать с него плату:

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

Я ищу алгоритм обработки указанного числа и разбивки его на количество вхождений в диапазоне. Как я могу сделать это на простом C # или LINQ?

------------ РЕДАКТИРОВАТЬ ----------------------------

Я задал менее запутанный вопрос ( Алгоритм схемы ценообразования Фогбугца ) и получил ответ, который искал.

Спасибо всем ..

Ответы [ 5 ]

2 голосов
/ 21 апреля 2010

Если представить такую ​​ценовую структуру, я думаю, что в интересах клиента минимизировать стоимость, покупая пакет, который лучше всего соответствует его потребностям. Следующий алгоритм использует динамическое программирование для расчета минимально возможной цены, чтобы точно купить определенное количество лицензий (вы можете сэкономить, купив больше, чем нужно, хотя я этого не реализовал):

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 долларов за штуку.

0 голосов
/ 21 апреля 2010

Я сделал для вас класс расчета ... просто более ориентированный на клиента. Он рассчитывает самую дешевую цену, возможную с указанными вами ценовыми диапазонами.

Пример: 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);
}
0 голосов
/ 21 апреля 2010

Если бы я был человеком, которому нужно 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 долл. США = 3220 долл. США

По моему мнению, первоначальный тарифный план дурацкий.Возьмите клиента, который купил 130 лицензий в прошлом году, который возвращается и хочет еще 10.Какое оправдание для того, чтобы взимать с них самую высокую ставку?Они являются крупными покупателями, вы хотите продать им (и они обоснованно рассчитывают получить) дополнительные лицензии по самой низкой «предельной» цене.

0 голосов
/ 21 апреля 2010

Похоже, это будет очень похоже на алгоритмы, которые делают изменения для покупок (какие монеты выбрать). Разница лишь в том, что вы сравниваете диапазон, а не одно число.

Код может выглядеть примерно так:

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;
}
0 голосов
/ 21 апреля 2010

Может быть, коллекция или словарь KeyValuePair?

...