幾何学的に考えると、購入したアイテムの総数 (横軸) の関数として合計価格 (縦軸) を示すグラフを考えてみましょう。プロットは(0, 0)
(ゼロを購入するとゼロの費用がかかります)で始まります。1.65
まず、勾配と水平幅の直線セグメントを取得します5000
。次に、その終点から、勾配1.6
と幅の新しいセグメントが来10000
ます。合計プロットは連続的で区分的に直線ですが、単価が変化する部分では曲がりがあります。
次に、問題を解決するには、方程式 の線y == 1.57 * x
、つまり から始まり(0, 0)
勾配 を持つ線との交点を見つけます1.57
。セグメント (2 つのエンドポイントを知っている) ごとに、このセグメントが を満たしているかどうかを確認し、満たしy == 1.57 * x
ていれば、解決策があります。
price
配列内の数値が減少している場合、最大で 1 つの解が存在する可能性があります (それ1.57
が最初の価格 よりも厳密に小さい場合price[0]
)、プロットは凹関数を表します。
編集: C# でこのジオメトリをコーディングしようとしました。price
私は、すべて正で減少している小切手を追加しませんでしたquantity
。すべて正です。それを確認する必要があります。これが私のコードです:
decimal[] price = { 1.65m, 1.6m, 1.55m, 1.4m, 1.3m, };
long[] quantity = { 5000, 10000, 12000, 20000, 50000, };
decimal desiredAverage = 1.57m;
int length = price.Length;
if (length != quantity.Length)
throw new InvalidOperationException();
var abscissaValues = new long[length + 1];
var ordinateValues = new decimal[length + 1];
for (int i = 1; i <= length; ++i)
{
for (int j = 0; j < i; ++j)
{
abscissaValues[i] += quantity[j];
ordinateValues[i] += price[j] * quantity[j];
}
} // calculation of plot complete
int segmentNumber = Enumerable.Range(1, length).FirstOrDefault(i => ordinateValues[i] / abscissaValues[i] <= desiredAverage);
if (segmentNumber > 1)
{
decimal x = (ordinateValues[segmentNumber - 1] * abscissaValues[segmentNumber] - abscissaValues[segmentNumber - 1] * ordinateValues[segmentNumber])
/ (desiredAverage * (abscissaValues[segmentNumber] - abscissaValues[segmentNumber - 1]) - (ordinateValues[segmentNumber] - ordinateValues[segmentNumber - 1]));
Console.WriteLine("Found solution x == " + x);
}
else
{
Console.WriteLine("No solution");
}
誰かがもっと美しく書けるかどうかはわかりませんが、うまくいくようです。出力は次のとおりです。
見つかった解 x == 29705.882352941176470588235294