基本情報技術者 2009年 秋期 午後 問11
次のJavaプログラムの説明及びプログラムを読んで、設問1,2に答えよ。
〔プログラムの説明〕
携帯電話の利用状況に対して、最も安価な料金プラン(割引サービスを含む)を提示するプログラムである。1か月の料金は、基本料金、通話料金及びパケット料金からなる。パケット料金にはオプションの割引サービスがある。
表1に料金プラン、表2にパケット料金の割引サービス、表3にテスト用の利用状況を示す。
なお、パケット料金を計算するとき、パケット数は100パケット単位に切り上げる。



(1) クラスCellPhonePlanは、料金プランを表す。メソッドcalculateChargeは、引数で渡された利用状況に対する料金を返す。
(2) クラスCallingPlanは、通話料金を計算するクラスである。メソッドcalculateChargeは、引数で渡された通話時間(分単位に切上げ)に対する料金を返す。
(3) インタフェースPacketPlanは、パケット料金を計算するためのインタフェースである。メソッドcalculateChargeは、引数で渡されたパケット数に対する料金を返す。
(4) クラスMeasuredは、従量制のパケット料金(割引サービスなしの場合)を表す。
(5) クラスTieredは、パケット料金の割引サービスS1を表す。
(6) クラスCellPhonePlannerは、利用状況に対して、最も安価な料金プラン(割引サービスを含む)を提示する。メソッドgetRecommendedPlanは、与えられた利用状況に対して、最も安価な料金プラン(割引サービスを含む)を返す。メソッドmainは、テスト用のメインプログラムである。
プログラムの実行結果を図に示す。







設問1:
問題文を見る プログラム中のに入れる正しい答えを、解答群の中から選べ。
aに関する解答群
ア:callingRate * minutes
イ:callingRate * minutes - included
ウ:included
エ:included - callingRate * minutes
bに関する解答群
ア:callingCharge < 0
イ:callingCharge < included
ウ:callingCharge > 0
エ:callingCharge > included
cに関する解答群
ア:extends CellPhonePlan
イ:extends PacketPlan
ウ:implements CellPhonePlan
エ:implements PacketPlan
dに関する解答群
ア:allowance + 99
イ:packets + 99
ウ:packets + allowance + 99
エ:packets - allowance + 99
e, fに関する解答群
ア:0
イ:Integer.MIN_VALUE
ウ:Integer.MAX_VALUE
エ:cellPhonePlan.calculateCharge(minutes, packets)
オ:recommended.calculateCharge(minutes, packets)
模範解答
a:イ、b:ア、c:エ、d:エ、e:ウ、f:エ
解説
解答の導き方
このプログラムでは、通話料金とパケット料金をそれぞれ計算し、料金プランの組合せの中から最も安いものを選びます。空欄は、料金計算の式とプログラムの流れを順に追うと判断できます。
通話料金の計算:a、b
表1では、基本料金に「無料通話分」が含まれています。したがって、通話時間に応じて計算した通話料金のうち、無料通話分を超えた金額だけを追加料金にします。
通話時間を 分、1分当たりの通話料金を 円、無料通話分を 円とすると、無料通話分を差し引いた金額は次の式です。
これが負の値なら、通話料金が無料通話分に収まっているということです。その場合、追加料金は 円にします。よって、aには「callingRate * minutes - included」、bには「callingCharge < 0」が入ります。
例えば、料金プランAで30分通話した場合、通話料金は 円です。無料通話分の1,000円を引くと200円なので、通話料金は基本料金2,000円に200円を加えた2,200円です。
料金プランBで30分通話した場合は、 円です。負の値なので、追加の通話料金は0円となり、通話料金は基本料金の3,000円です。
PacketPlanを実装する:c
プログラム3では、PacketPlanが「calculateCharge」などのメソッドを定めています。このように、クラスに必要なメソッドの形を示すものをインタフェースといいます。
MeasuredとTieredは、どちらもパケット料金を計算するクラスです。両方がPacketPlanに定められたメソッドを用意するため、クラスの宣言にはインタフェースを実装することを表す「implements」を使います。したがって、cには「implements PacketPlan」が入ります。「extends」はクラスを継承するときに使うもので、この場合には当てはまりません。
従量制のパケット料金
問題文には「パケット数は100パケット単位に切り上げる」とあります。Measuredでは、100パケットごとの料金に、切り上げた単位数を掛けています。
プログラム中の「(packets + 99) / 100」は、パケット数を100で割ったときの端数を切り上げる式です。例えば、1,000パケットなら10単位、1,001パケットなら11単位になります。1,000パケットの料金は、100パケット当たり20円なので、 円です。
割引サービスの料金計算:d
Tieredでは、まずサービス料金の1,000円を料金に設定します。さらに、パケット数がallowanceを超えた場合だけ、超えた分の料金を加えます。
超過分は です。この超過分を100パケット単位で切り上げるため、dには「packets - allowance + 99」が入ります。式全体では、超過分の単位数を次のように計算しています。
この計算が行われるのは、パケット数がallowanceを超えた場合だけです。S1ではallowanceが10,000パケットなので、10,000パケットまではサービス料金の1,000円だけで、超えた分には100パケット当たり8円が加算されます。
最も安いプランを選ぶ:e、f
プログラムは、複数の料金プランを順に調べ、現在の最安料金より安いものがあれば、そのプランを最安候補として記録します。
まだ1つも料金を調べていない段階では、minChargeを非常に大きな値にしておきます。そうすれば、最初に計算した料金が必ずminCharge以下になり、最初のプランが候補に記録されます。JavaのInteger.MAX_VALUEは整数として扱える最大値なので、eには「Integer.MAX_VALUE」が入ります。
繰返し処理の中では、今調べているプランの料金を計算します。対象のプランはループ変数cellPhonePlanが表しているため、fには「cellPhonePlan.calculateCharge(minutes, packets)」が入ります。計算した料金がminCharge以下なら、そのプランをrecommendedに記録し、minChargeも更新します。
テスト用の利用状況で確認する
表3の各利用状況について、4種類の料金プランの組合せを比較すると、次のようになります。料金プランの組合せは、AまたはBと、割引なしまたはS1との組合せです。
例えば、通話時間が30分、パケット数が1,000の場合、Aの通話料金は2,200円、従量制のパケット料金は200円です。合計は2,400円となり、ほかの組合せより安くなります。
一方、通話時間が30分、パケット数が10,000の場合、A S1の料金は、Aの通話料金2,200円とS1のサービス料金1,000円を合わせた3,200円です。割引なしのパケット料金は2,000円かかるため、A S1の方が安くなります。
通話時間が300分の場合、Aの通話料金は 円で、基本料金と合わせて13,000円です。Bは 円で、基本料金と合わせて10,000円です。通話時間が長いとBの方が安くなります。
誤りやすいポイント
- 無料通話分は、通話時間から差し引く時間ではなく、基本料金に含まれている金額です。そのため、通話料金の金額からincludedを引きます。
- 通話料金の追加分が負の値になったときは、0円にします。負の料金を基本料金から差し引くわけではありません。
- S1の割引対象は、パケット数全体ではなくallowanceを超えた分です。超過分を計算する式では、packetsからallowanceを引きます。
- 最安料金を探すとき、minChargeを0で初期化すると、通常の料金が0円以下でない限り候補が選ばれません。最初の候補を確実に記録できるよう、大きな値で初期化します。
- 料金を比べるのは、料金プランAとBだけではありません。通話プランとパケットプランの組合せをすべて調べます。
FAQ
Q: S1の料金は、パケット数が10,000のときも1,000円ですか?
A: はい。表2では10,000パケットまでは無料とされているため、パケット料金はかかりません。ただし、S1のサービス料金1,000円はかかります。
A: はい。表2では10,000パケットまでは無料とされているため、パケット料金はかかりません。ただし、S1のサービス料金1,000円はかかります。
Q: 料金が同じプランがあった場合、どれが選ばれますか?
A: 条件が「charge <= minCharge」なので、同じ料金の場合も後から調べたプランが候補に記録されます。このテスト用の利用状況では、最安のプランが同額になるケースはありません。
A: 条件が「charge <= minCharge」なので、同じ料金の場合も後から調べたプランが候補に記録されます。このテスト用の利用状況では、最安のプランが同額になるケースはありません。
Q: 「(packets + 99) / 100」で切り上げられるのはなぜですか?
A: 100で割る前に99を足すことで、100で割り切れない分があれば、商が次の整数になります。例えば、1,001パケットでは「(1,001 + 99) / 100」が11となり、必要な100パケット単位数を切り上げられます。
A: 100で割る前に99を足すことで、100で割り切れない分があれば、商が次の整数になります。例えば、1,001パケットでは「(1,001 + 99) / 100」が11となり、必要な100パケット単位数を切り上げられます。
関連キーワード: インタフェース、実装、整数除算、切上げ、最小値探索
設問2:
問題文を見る パケット通信を大量に行う人を対象として、S1の内容を変更したパケット料金割引サービスS2を追加することにした。表4にサービスの内容、プログラム7にS2を表すクラスを示す。プログラム7中のに入れる正しい答えを、解答群の中から選べ。


gに関する解答群
ア:extends PacketPlan
イ:extends Tiered
ウ:implements PacketPlan
エ:implements Tiered
h, iに関する解答群
ア:0
イ:allowance
ウ:basicCharge
エ:basicCharge + maxCharge
オ:maxCharge
カ:super.calculateCharge(packets)
キ:this.calculateCharge(packets)
模範解答
g:イ、h:カ、i:オ
解説
解答の導き方
この問題では、既存の割引サービスの計算を利用しながら、パケット料金に上限を設けるクラスを作ります。
-
g:どのクラスを引き継ぐかクラスは、データや処理をまとめる設計図です。既存のクラスの性質を引き継いで、新しい処理を加える仕組みを「継承」といいます。既存のTieredは、基本料金、無料となるパケット数、超過分の料金を使って計算します。S2もこの計算方法を使い、さらに料金の上限を設けるサービスです。そのため、TieredBoundedはTieredを継承します。クラスの継承を表す書き方はextendsなので、gにはextends Tieredが入ります。また、プログラム7のコンストラクタ(オブジェクトを作るときに初期化する処理)には、super(name, basicCharge, allowance, packetRate)があります。superは継承元のクラスを指すため、継承元はこの引数を受け取るTieredだと分かります。PacketPlanは、必要なメソッドを定めるインタフェース(クラスに実装してほしい処理の約束)です。インタフェースを実装するときはimplementsを使います。一方、Tieredはクラスなので、ここではimplementsではなくextendsを使います。
-
h:上限を適用する前の料金をどう計算するかS2は、まずTieredと同じ方法で料金を計算し、その結果が上限を超えたときに上限額へ置き換えます。そのため、hには継承元TieredのcalculateChargeを呼び出すsuper.calculateCharge(packets)が入ります。これなら、既存の計算処理をそのまま利用できます。this.calculateCharge(packets)を使うと、今作っているTieredBoundedのcalculateChargeをもう一度呼び出します。同じ処理を繰り返してしまうため、料金を計算できません。
-
i:比較する上限額はどれか表4では、50,000パケットを超えた場合も料金は一律5,000円です。Tieredの計算で求めた料金が上限額より大きいとき、その料金を上限額に置き換える必要があります。S2では、50,000パケットのときに、基本料金1,000円に超過分の料金4,000円を足すと、合計は5,000円になります。したがって、上限額を表すmaxChargeと比較します。条件式はcharge > maxChargeとなり、iにはmaxChargeが入ります。
誤りやすいポイント
-
gでimplementsを選ぶこと
implementsはインタフェースを実装するときに使います。TieredBoundedが引き継ぐ相手はクラスのTieredなので、extendsを選びます。 -
hでthis.calculateCharge(packets)を選ぶこと
thisは、今処理しているオブジェクト自身を指します。同じメソッドを自分自身から呼ぶため、計算が終わらず繰り返されます。継承元の計算を使うにはsuperを指定します。 -
iでbasicChargeを選ぶこと
basicChargeはサービスの基本料金であり、料金の上限ではありません。S2では超過分も含めた料金全体を5,000円までにするため、比較するのはmaxChargeです。
FAQ
Q: S2でTieredの計算を使うのはなぜですか?
A: 無料となるパケット数や超過分の料金計算は既存のTieredで行い、S2で追加する上限処理だけをTieredBoundedに加えるためです。
A: 無料となるパケット数や超過分の料金計算は既存のTieredで行い、S2で追加する上限処理だけをTieredBoundedに加えるためです。
Q: 料金がmaxChargeと同じ場合も、上限額に置き換えますか?
A: 条件はcharge > maxChargeです。料金が上限額と同じなら、そのまま返しても上限額に置き換えても結果は同じです。
A: 条件はcharge > maxChargeです。料金が上限額と同じなら、そのまま返しても上限額に置き換えても結果は同じです。
Q: パケット数を100パケット単位に切り上げる処理は、どこで行いますか?
A: Tieredの料金計算で行います。TieredBoundedはその計算結果を受け取り、上限を超えた場合だけ料金を抑えます。
A: Tieredの料金計算で行います。TieredBoundedはその計算結果を受け取り、上限を超えた場合だけ料金を抑えます。
関連キーワード: 継承、インタフェース、メソッド呼出し、上限処理、切上げ計算



