基本情報技術者 2009年 春期 午後 問08
次のプログラムの説明及びプログラムを読んで、設問に答えよ。
〔プログラムの説明〕
64(8×8)画素からなる表示領域がある。この表示領域中の一つの画素を指定して、その画素を含む同じ色の領域を、指定した色で塗り替えるプログラムである。
ある一つの画素について、その画素の上下左右の4方向に隣接した画素の中に同じ色のものがあれば、それらの画素は同じ色の領域内にあるものと判定する。このようにして領域内にあると判定された隣接する各画素について、同様の判定を繰り返し、指定した色で塗り替えていく。
(1) 大きさ10×10の2次元配列Image(各添字の範囲は0〜9)を用意する。各画素の色は、配列Imageの一部(各添字の範囲は1〜8)に保持する。
(2) 色は、黒(■)、灰(▒)、白(□)の3色で、それぞれを値1、2、3で表す。
(3) 塗り替えたい領域中の開始点を示す一つの画素を、変数VSとHSで指定する。VSとHSは、その画素に対応する配列Imageの要素の縦と横方向の添字である。
(4) 塗り替えたい色を、変数NCで指定する。
(5) プログラムは、Image[VS, HS]から現在の画素の色を取得し、その画素を含む同じ色の領域を、色NCで塗り替える。
(6) 大域変数Image、NC、VS、HSには、正しい値が設定されているものとする。
(7) 配列VPos、HPosの添字は、1から始まる。
(8) 図1は、VS = 5、HS = 3として、Image[5, 3]を塗り替えたい領域内の開始点に指定し、NC = 1として、塗り替える色を黒(■)に指定した場合の、プログラムの実行例である。

設問1:
問題文を見る 次の記述中のに入れる正しい答えを、解答群の中から選べ。
このプログラムに関する先輩技術者(以下、先輩という)と新人技術者(以下、新人という)の会話である。
先輩:プログラムの動作を理解するには、処理の流れを追跡してみることが大切です。まず、画素の色がどのような順序で塗り替えられていくか、図1のデータが与えられたものとして、最初の五つが塗り替えられる順序を1、2、…、5で示してみてください。
新人:はい。追跡してみます。結果は、aのようになりました。
先輩:そうですね。では、プログラムを検討していきましょう。まず、元の画素数は8×8ですが、配列Imageの大きさは10×10で、行番号15〜23で最外周の配列要素に値0を設定しています。これは何のための処理でしょうか。
新人:はい、bからです。しかし、表示領域の要素数64に対して、32の配列要素に値を設定するのは、随分無駄な処理のように思えます。
先輩:では、一般にm×n画素からなる表示領域を考えたとき、行番号15〜23で値を設定する要素数は、どういう式で表せますか。
新人:はい、cとなります。ということは、表示領域の画素数m×nが大きくなるほど、この要素数は相対的に小さくなっていくのですね。
先輩:次に、最外周の配列要素に設定する値について考えてみましょう。行番号15では、変数Wallに値0を設定しています。与えられた仕様では、画素の色を表す値は1〜3の範囲だからこれでよいのですが、もしも、符号なし8ビットで表せる値0〜255がすべて色の指定に使えるとした場合、行番号15をどう変更したらよいですか。例を一つ挙げてみてください。
新人:行番号15をdと変更するのも一つの方法です。
先輩:次は、行番号12〜14について考えてみます。これは何の処理ですか。
新人:現在の色と同じ色で塗り替えようとしているなら、以降の処理をせずに呼出し元に戻ります。塗り替えても、結局元どおりなので無駄ですから。
先輩:それも理由の一つではあるけれど。では、このプログラムから行番号12〜14を取り去ってみましょう。そして、図2の①〜③に示す、1画素、2画素、3画素からなる三つの白色の領域の例について、同じ色で塗り替えようとした場合のプログラムの動作を追跡してみてください。変数VS、HSには、太枠で示した画素を指定するものとします。

新人:では、追跡してみます。結果は、次の表のとおりです。この結果から、行番号12〜14は省略できない必要な処理であることが分かりました。
aに関する解答群

bに関する解答群
ア:これらの要素が参照されることはないが、添字から表示領域内かどうかが分かる
イ:これらの要素も色NCでの塗替えの対象とすることで、処理を簡素化できる
ウ:配列Imageの各添字の範囲チェックを省略できる
エ:配列VPosとHPosの各添字の範囲チェックを省略できる
cに関する解答群
ア:2(m + 1)(n + 1)
イ:2(m + n)
ウ:2(m + n + 2)
エ:2(m + n − 2)
dに関する解答群
ア:・Wall ← CC
イ:・Wall ← NC
ウ:・Wall ← 256 − CC
エ:・Wall ← 255 − NC
e, fに関する解答群
ア:仕様どおりに同じ色で塗り替えて正しく終了する。
イ:塗替えは一度も実行せずに終了する。
ウ:塗り替えるべき領域に含まれない周辺の画素まで塗り替えて終了する。
エ:変数Moreの値が増加していき配列の添字の上限を超える。
オ:変数Moreの値は一定値以下であるが処理が無限にループする。
模範解答
a:イ、b:ウ、c:イ、d:イ、e:ア、f:オ
解説
解答の導き方
このプログラムは、開始点と同じ色で、上下左右につながっている画素を探し、見つけた画素を順に塗り替えます。画素を見つけたときに、位置を配列に登録しておき、あとから登録した画素から処理します。
a:画素が塗り替えられる順序
図1では、開始点はImage[5, 3] です。その画素の色をCCに取り込み、塗り替える色NCは黒(値1)です。
CheckAndStackは、対象の画素がCCと同じ色なら、すぐにNCに塗り替えてから、その位置をVPosとHPosに登録します。そのため、塗り替えられた順番が、選択肢の数字の順番になります。
Mainは、登録した画素のうち、最後に登録した画素を次の処理対象にします。処理対象の上下左右を「上、左、下、右」の順で調べ、同じ色の画素があれば塗り替えて登録します。この順序を追うと、最初の5画素の並びは選択肢イです。
b:最外周に値を設定する理由
配列Imageの画素部分は添字が1〜8です。その外側にある添字0と9の要素には、Wallの値を設定します。
こうすると、画素の隣を調べるとき、表示領域の端にある画素から外側へ進んでも、配列の範囲外を参照しません。さらに、外周の値は色を表す値と異なるため、外周を同じ色の領域だと誤って判定することもありません。
つまり、Imageの添字が範囲内かどうかを、毎回確認しなくて済みます。これが選択肢ウです。
c:外周に値を設定する要素数
一般に、表示領域が 行 列の場合を考えます。
- 左右の外側の列には、それぞれ 個ずつ設定します。合計は 個です。
- 上下の外側の行には、それぞれ 個ずつ設定します。合計は 個です。
行番号15〜23の処理では、四隅は設定していません。したがって、設定する要素数は、
です。選択肢ではイに当たります。
d:色に0〜255の値を使う場合のWall
このプログラムは、行番号12〜14でCCとNCが同じなら、すぐに終了します。したがって、ここまで処理が進んだ場合は、CCとNCは異なります。
外周の値を NC にすれば、外周の値は CC と異なります。そのため、外周を同じ色の領域だと判定することはありません。よって、行番号15は「Wall ← NC」と変更できます。選択肢ではイです。
ほかの値の決め方では、CCと同じ値になる可能性があります。たとえばWallをCCにすると、外周まで同じ色だと判定されてしまいます。
e:図2の①(1画素の領域)
行番号12〜14を取り除くと、塗り替える色NCがCCと同じでも、処理を開始します。
図2の①では、開始点を登録してから取り出し、その上下左右を調べます。周囲は別の色なので、同じ色の画素は新たに登録されません。処理待ちの画素がなくなり、プログラムは終了します。
この場合、画素の値は元の色のままです。もともと塗り替える色と同じ色なので、結果は仕様どおりです。選択肢はアです。
f:図2の②(2画素の領域)
2画素の領域では、開始点を処理すると、隣の画素が同じ色として登録されます。しかし、NCとCCが同じなので、登録時に画素の値は変わりません。
次に隣の画素を処理すると、今度は最初の画素がまだ同じ色のままなので、再び登録されます。このように、2画素が互いを何度も登録し合います。Moreの値は大きくならず、処理が終わらないため、選択肢はオです。
なお、図2の③のように3画素がつながっている場合は、中央の画素から両隣の画素が登録されます。登録された画素の重複が増えてMoreの値も増加し、やがて配列の添字の上限を超えます。
誤りやすいポイント
- VPosとHPosは、画素の位置を記録する配列です。Moreは、処理待ちの画素が何個あるかを表します。Moreを添字として使い、最後に登録した画素を取り出します。
- 画素を登録するときにすぐ塗り替える処理には、同じ画素を何度も登録しない役割があります。塗り替え後の色NCは、処理開始時点ではCCと異なるため、再び調べても「同じ色」と判定されません。
- 図2の②と③では、NCとCCが同じです。そのため、登録時に画素の色が変わらず、すでに登録した画素を見分けられません。
- 外周の要素数を数えるとき、四隅を含めてはいけません。行番号15〜23では、左右の外側の列と上下の外側の行のうち、四隅以外を設定しています。
FAQ
Q: Moreが0になると、なぜ処理が終わるのですか?
A: Moreは処理待ちの画素の数です。登録されている画素をすべて取り出すと0になり、行番号26の反復条件を満たさなくなるため、繰返しが終了します。
A: Moreは処理待ちの画素の数です。登録されている画素をすべて取り出すと0になり、行番号26の反復条件を満たさなくなるため、繰返しが終了します。
Q: 同じ色で塗り替える場合、画素の色が変わらなくても問題ありませんか?
A: 結果として画素の見た目は変わりません。ただし、行番号12〜14がないと、プログラムは画素の色が変わったかどうかで処理済みかを判断できず、同じ画素を再登録することがあります。図2の②や③がその例です。
A: 結果として画素の見た目は変わりません。ただし、行番号12〜14がないと、プログラムは画素の色が変わったかどうかで処理済みかを判断できず、同じ画素を再登録することがあります。図2の②や③がその例です。
Q: このプログラムで、配列の外側に値を設定するのはなぜですか?
A: 端の画素の隣を調べるときも、配列の範囲外を参照せずに済むようにするためです。外周の値がCCと異なれば、外側が塗替え対象に加わることもありません。
A: 端の画素の隣を調べるときも、配列の範囲外を参照せずに済むようにするためです。外周の値がCCと異なれば、外側が塗替え対象に加わることもありません。
関連キーワード: 領域塗りつぶし、スタック、深さ優先探索、番兵、境界チェック




