Cygwinでデバッグ/例題3

価格の割引

ある市販のソフトウェアAとソフトウェアBがある。 このソフトウェアの価格には、購入本数に応じた値引きがあり、 1本あたりの単価が購入本数に応じて決まる。 このため、価格設定によっては「購入本数の多いほうが、購入総額が安くなる」という 逆転現象が起こることがある。 この逆転現象について調査するプログラムを、以下の指示に従って作りなさい。

いくつかの関数を作ることになるが、作りたいプログラムは全体で1つである。 main() 関数の処理内容は、徐々に変化していく。

ソフトウェアA

まず、ソフトウェアAについて考える。 単価は以下のようになっている。

本数単価
~4本5000円
5~9本4500円
10本~3500円
  1. 購入本数 n に応じた単価を計算する関数
    int priceA(int n)
    を作りなさい。

    ヒント:条件分岐に無駄がないように注意せよ。

  2. 購入本数 n に応じた購入総額を計算する関数
    int total_priceA(int n)
    を作りなさい。n は 0 以上であることを前提としてよい。

    ヒント:この関数に条件分岐が必要か、よく検討せよ。

  3. main() 関数で、購入本数を20から1まで変化させ、それぞれの本数について、次の項目を表示しなさい。
    • 購入本数
    • 単価
    • 総額
    • これまで表示した総額の最小値
  4. 3. で作った main() 関数を改造して、逆転現象の起こっている部分(もっと多い本数を購入すると総額が安くなるケース)のみを表示するようにしなさい。

    ヒント:総額の最小値を更新しなかった場合に限って表示すればよい。

ソフトウェアB

次に、ソフトウェアBについて考える。 単価は以下のようになっている。

本数単価
~4本5000円
5~9本4800円
10~14本4600円
15~19本4500円
20~49本4300円
50~79本4100円
80~99本3600円
100~999本3500円
1000本~3300円

このように価格表が大きく複雑であるので、 価格の改定があった場合にプログラムの修正作業が楽になるように工夫したい。 つまり、ソフトウェアAの場合とは違う構造のプログラムを作りたい。

  1. ソフトウェアAの場合と同様に、購入本数 n に応じた単価を計算する関数
    int priceB(int n)
    を作りなさい。ただし、プログラム(関数)の中に価格を直接書き込むのではなく、 配列に価格を書き並べるようにしなさい。 例えば、次のような2つの配列を大域変数(グローバル変数)に宣言するとよい。 (これ以外の配列の使い方をしてもよい。)
    int pricesB[] = { 5000, 4800, 4600, 4500, 4300, 4100, 3600, 3500, 3300 };
    int numsB[]   = {    5,   10,   15,   20,   50,   80,  100, 1000, -1   };

    ヒント:numsB[] 配列を先頭要素から順番にアクセスするループは

    for (i=0; numsB[i] >= 0; i++) { ... }

    のように書ける。 参考までに、配列の最後を表す特別な値(-1)の要素は、「番兵」と呼ばれる。

  2. ソフトウェアAの場合と同様に、購入本数 n に応じた購入総額を計算する関数
    int total_priceB(int n)
    を作りなさい。

    ヒント:total_priceA() で条件分岐をした人は、ここでもう一度考えなおして欲しい。条件分岐をせずにすませた人は、その利点を改めて感じ取って欲しい。

  3. 購入者が注文してきた時に、逆転現象の起こる本数であれば 「何本購入すればもっと安くなります」と提案したい。 そこで、必要とされる本数 n 以上で、もっとも総額が安価になる本数を返す関数
    int suggestB(int n)
    を作りなさい。 簡単のため、1000本よりも多く購入しても、それ以上は単価の値引きが起こらないことを利用してもよい。

    ヒント1:関数の動作としては、逆転現象の起こらない場合は、 与えられた n をそのまま返すことになる。

    ヒント2:1000という数値に依存しない関数を記述できると、なおよい。-1 という数値は番兵をあらわすので、依存してよい。


トップ   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS