基本情報技術者 2016年 秋期 午後 問09
次のCプログラムの説明及びプログラムを読んで、設問1,2に答えよ。
〔プログラム1の説明〕
U社では、半年ごとに社内システムの見直しを行い、4月と10月に新たに開発又は改修するサブシステム(以下、対象サブシステムという)を決定し、開発又は改修作業(以下、開発作業という)を実施している。対象サブシステムは複数あり、それぞれに対して目標作業終了日が設定される。二つ以上の対象サブシステムの開発作業を同時に実施することはない。各対象サブシステムについて、開発リソースの制約があるので、必ずしも目標作業終了日までに開発作業を終了できるとは限らない。しかし、開発作業の終了が目標作業終了日よりも遅れる日数(以下、遅延日数という)の合計はできるだけ少なくしたい。そこで、対象サブシステムの開発作業順序を求める関数job_schedulingを作成した。
(1) 関数job_schedulingの仕様は次のとおりである。ここで、引数の値に誤りはないものとする。
機能: 対象サブシステムの開発作業順序を求める。
引数: num_s 対象サブシステム数
job 対象サブシステム情報(JOB型の配列)
job_sch 開発作業順序(int型の配列)
(2) 構造体を使ったJOB型の定義は次のとおりである。
typedef struct {
char pr_code[9]; /* 開発コード */
int job_term; /* 開発作業日数 */
int target_term; /* 目標作業期間 */
} JOB;
① 開発コードは、対象サブシステムごとに一意となる長さが8の文字列
② 開発作業日数は、開発作業に掛かる日数
③ 目標作業期間は、半年ごとの一連の開発作業を開始する日から、この対象サブシステムの目標作業終了日までの日数
(3) 対象サブシステム情報jobには、次の①~③の順で、データが格納されている。
① 目標作業期間の昇順
② 目標作業期間が同じならば、開発作業日数の昇順
③ 目標作業期間も開発作業日数も同じならば、開発コードの昇順
(4) (5)の手順で、開発作業順序を求めると、開発作業順序job_schの要素job_sch[i]には、i + 1番目(i = 0, 1, …, num_s − 1)に開発作業を実施する対象サブシステムの情報が格納されたjob[j]の添字の値j (j = 0, 1, …, num_s − 1)が入る。
(5) 開発作業順序を求める手順は、次のとおりである。
① 開発作業順序job_schを、対象サブシステム情報jobの並び順に初期設定し、開発作業順序の添字iに初期値0を設定する。
② i < num_s − 1である間、③~⑥の処理を行う。
③ i + 1番目に開発作業を実施する対象サブシステムjob[job_sch[i]]とi + 2番目に開発作業を実施する対象サブシステムjob[job_sch[i + 1]]の開発作業を、順序どおりに実施した場合の二つの対象サブシステムの遅延日数の合計wt_aと、順序を入れ替えて実施した場合の二つの対象サブシステムの遅延日数の合計wt_bを求める。
④ 開発作業の実施順序を入れ替えることによって遅延日数の合計が減る場合(wt_a > wt_b)には、開発作業の実施順序を入れ替える。
⑤ 開発作業の実施順序を入れ替えた場合、iが0でなければ、iを1減らす。
⑥ 入れ替えなかった場合、iを1増やす。
(6) i番目の対象サブシステムの開発作業が終わるまでの開発作業日数の合計をftとしたとき、i + 1番目の対象サブシステムの開発作業が終わったときの遅延日数wtは、次式で求められる。
ここで、job_termとtarget_termは、i + 1番目に開発作業を実施する対象サブシステムの開発作業日数と目標作業期間である。

設問1:
問題文を見る プログラム1中のに入れる正しい答えを、解答群の中から選べ。
aに関する解答群
ア:i + j
イ:i + j - 1
ウ:i - j
エ:i - j + 1
bに関する解答群
ア:i + 1
イ:i - 1
ウ:job_no
エ:job_no + 1
オ:job_no - 1
cに関する解答群
ア:i + 1
イ:i - 1
ウ:i++
エ:i--
オ:++i
カ:--i
dに関する解答群
ア:=
イ:+=
ウ:-=
模範解答
a:エ、b:ア、c:カ、d:イ
解説
解答の導き方
このプログラムは、隣り合う二つの対象サブシステムについて、順番を入れ替えた方が遅延日数の合計が少なくなるかを調べます。
ここで、開発作業順序の配列 には、対象サブシステム情報の配列 の何番目の情報を使うかが入っています。配列の「添字」は、要素の位置を表す番号です。したがって、 の要素を入れ替えると、開発作業の順番が変わります。
1. aは、入れ替えた順番で見る位置を表します
問題文では、 は現在の順番、 は順番を入れ替えた場合の遅延日数の合計です。プログラムの繰返しでは を 、 と変えながら、二つの対象サブシステムの遅延日数を計算します。
現在の順番では、見る位置は です。一方、入れ替えた順番では、最初に現在の二つ目、次に現在の一つ目を見ます。
- のとき、入れ替えた順番で見るのは位置
- のとき、入れ替えた順番で見るのは位置
この二つを表す式は です。よって、aには「エ」が入ります。
2. bは、入れ替える位置を表します
入れ替えるのは、現在の位置 と、その次の位置です。次の位置は なので、 と を入れ替えます。
プログラムでは、最初に位置 の値を一時的に保存し、位置 の値を位置 に移し、保存した値を位置 に戻します。したがって、bには「ア」が入ります。
3. cは、順番を入れ替えた後に確認する位置を表します
変数 は、現在調べている位置 より前にある対象サブシステムの開発作業日数の合計です。
位置 と の順番を入れ替えると、その一つ前の組合せにも影響する可能性があります。そのため、 が より大きければ、位置を一つ戻して、前の組合せから確認し直します。
位置を戻すには、 を先に一つ減らし、その位置の対象サブシステムの開発作業日数を から引きます。選択肢では が該当するため、cには「カ」が入ります。
ここで は、 を先に一つ減らしてから、その値を配列の位置として使う書き方です。 のように後から減らす書き方では、配列の位置に減らす前の値が使われてしまいます。
4. dは、順番を入れ替えなかった場合の更新です
順番を入れ替えなかった場合、位置 の対象サブシステムをそのまま確定し、開発作業日数を に加えます。その後、次の組合せを調べるために を一つ進めます。
この処理は、 に開発作業日数を加える演算子で表します。したがって、dには「イ」が入ります。式の中の は、現在の の位置を使ってから、 を一つ増やします。
図1の値で処理を確認します
最初は、順番が 、 で、、 です。
- 現在の順番では、 は25日目に終了し、目標の27日以内なので遅延は0日です。続く は52日目に終了し、目標の29日を23日超えるため、遅延日数の合計は23日です。
- 入れ替えた順番では、 は27日目に終了して遅延は0日です。続く は52日目に終了し、目標の27日を25日超えるため、遅延日数の合計は25日です。
現在の順番の方が遅延日数の合計は少ないので、入れ替えません。位置0の開発作業日数25日を に加え、 を1に進めます。
次に、 と を比べます。現在の順番では、遅延日数の合計は66日です。入れ替えると60日です。入れ替えた方が少ないので、順番を入れ替えます。その後、 を一つ戻して前の組合せを確認できるようにし、 から位置0の開発作業日数25日を引きます。
このように、入れ替えたときは前の位置に戻り、入れ替えなかったときは今の作業を確定して次の位置へ進みます。
誤りやすいポイント
- 入れ替えた順番を計算するとき、位置を のままにしないようにします。二つの要素を逆順に見るので、式は です。
- 入れ替えるのは位置 と です。対象サブシステム情報そのものではなく、順番を表す配列の要素を交換します。
- と は、配列の位置に使われる値が異なります。このプログラムでは、減らした後の位置を使う必要があります。
- 入れ替えなかった場合は、開発作業日数を に加えます。遅延日数を足すのではありません。
FAQ
Q: 遅延日数の合計が同じ場合も、入れ替えますか?
A: 入れ替えません。条件は なので、入れ替えた場合に遅延日数の合計が小さくなるときだけ交換します。
A: 入れ替えません。条件は なので、入れ替えた場合に遅延日数の合計が小さくなるときだけ交換します。
Q: 順番を入れ替えた後、なぜ前の位置に戻るのですか?
A: 位置 の対象サブシステムが変わると、その一つ前の位置との組合せも変わります。前の組合せも調べ直すためです。
A: 位置 の対象サブシステムが変わると、その一つ前の位置との組合せも変わります。前の組合せも調べ直すためです。
Q: から差し引くのは、なぜ一つ前の対象サブシステムの開発作業日数ですか?
A: を一つ戻すと、 より前として数える範囲も一つ短くなります。その範囲から外れる対象サブシステムの開発作業日数を差し引きます。
A: を一つ戻すと、 より前として数える範囲も一つ短くなります。その範囲から外れる対象サブシステムの開発作業日数を差し引きます。
関連キーワード: 配列、添字、構造体、ループ、条件分岐、隣接交換
設問2:
問題文を見る 関数job_schedulingを実行したときに得られる対象サブシステムの開発作業順序などを出力する関数print_scheduleを作成した。次の記述中のに入れる正しい答えを、解答群の中から選べ。
(1) 関数print_scheduleの仕様は次のとおりである。ここで、引数の値に誤りはないものとする。
機能: 対象サブシステムの開発作業順序などを出力する。
引数: num_s 対象サブシステム数
job 対象サブシステム情報(JOB型の配列)
job_sch 開発作業順序(int型の配列)
(2) 図1に示す五つの対象サブシステムの対象サブシステム情報に対して関数job_schedulingを実行した。このときに得られた開発作業順序を、図2に示す。


(3) 続けて、関数print_scheduleを実行した。その出力結果の3行目を図3に示す。


e, fに関する解答群
ア:0
イ:27
ウ:44
エ:46
オ:57
カ:60
キ:73
ク:86
模範解答
e:ウ、f:カ
解説
解答の導き方
図3の3行目に出力される値を求めます。図2では、3番目に作業する対象サブシステムの情報として、job_sch[2] に1が入っています。したがって、対象はjob[1] です。
図1を見ると、job[1] の開発コードはGGL08001、開発作業日数は27、目標作業期間は29です。
print_scheduleは、作業が終わるまでの日数の合計をftに加え、その作業の遅延日数をwtに入れます。また、遅延日数をwt_sumに加算して累計します。出力する値は、作業順、開発コード、wt、wt_sumの順です。
3番目の作業では、作業終了までの日数の合計ftは73です。目標作業期間の29を超えているので、その作業の遅延日数wtは です。
一方、wt_sumはそれまでの遅延日数も含めた累計です。2番目の作業までの累計16に、3番目の遅延日数44を加えるため、 です。よって、図3の3行目では、開発コードの後に44、その右に60が出力されます。
誤りやすいポイント
- 作業順の3番目だからといって、対象がjob[2] になるわけではありません。job_sch[2] の値が1なので、対象はjob[1] です。
- wtはその作業の遅延日数、wt_sumは遅延日数の累計です。3番目の作業のwtは44ですが、wt_sumは60です。
- 目標作業期間と比べるのは、その作業だけの開発作業日数ではありません。先行する作業も含めた終了までの日数の合計ftです。
FAQ
Q: 3番目の作業の遅延日数が44になるのはなぜですか?
A: 3番目の作業が終わるまでに73日かかり、目標作業期間が29日だからです。超過した日数は です。
A: 3番目の作業が終わるまでに73日かかり、目標作業期間が29日だからです。超過した日数は です。
Q: 右端の値が44ではなく60なのはなぜですか?
A: 右端に出力される値は、遅延日数の累計だからです。2番目までの累計16に、3番目の遅延日数44を加えた値が60です。
A: 右端に出力される値は、遅延日数の累計だからです。2番目までの累計16に、3番目の遅延日数44を加えた値が60です。
関連キーワード: 配列、構造体、累計計算、条件分岐、書式指定



