ITの基礎知識|ITパスポート・基本情報

基本情報技術者 平成21年春 午後 問8

2026.05.23

午後問題に共通する注意事項(表記ルールなど)については、下記のリンク先を参照してください。

基本情報技術者 平成21年春 午後問題の注意事項


問題

次のプログラムの説明及びプログラムを読んで,設問に答えよ。

【プログラムの説明】

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  ○符号なし8ビット整数型: Image[10, 10]    /* 画素の色情報 */
  2  ○整数型: VS, HS                          /* 開始点はImage[VS,HS] */
  3  ○符号なし8ビット整数型: CC, NC           /* 色CCの領域を色NCで塗替え */
  4  ○整数型: More                             /* 処理待ちの画素の数 */
  5  ○整数型: VPos[64], HPos[64]              /* 処理待ちの画素の位置情報 */
  6
  7  ○プログラム: Main
  8  ○整数型: V, H                             /* 縦(V)と横(H)方向の添字用 */
  9  ○符号なし8ビット整数型: Wall              /* 表示領域の外周に格納する値 */
 10
 11  ・CC ← Image[VS, HS]                     /* 開始点の現在の色を取得 */
 12  ▲ CC = NC
 13  │  ・Return                               /* 処理を終了 */
 14  ▼
 15  ・Wall ← 0
 16  ■ V: 1, V ≦ 8, 1                        /* Vを1~8として外周に値を設定 */
 17  │  ・Image[V, 0] ← Wall
 18  │  ・Image[V, 9] ← Wall
 19  ■
 20  ■ H: 1, H ≦ 8, 1                        /* Hを1~8として外周に値を設定 */
 21  │  ・Image[0, H] ← Wall
 22  │  ・Image[9, H] ← Wall
 23  ■
 24  ・More ← 0
 25  ・CheckAndStack(VS, HS)                   /* 開始点を処理待ちの画素として登録 */
 26  ■ More > 0                               /* More>0の間,次の処理を繰り返す。*/
 27  │  ・V ← VPos[More]
 28  │  ・H ← HPos[More]
 29  │  ・More ← More − 1
 30  │  ・CheckAndStack(V − 1, H)
 31  │  ・CheckAndStack(V, H − 1)
 32  │  ・CheckAndStack(V + 1, H)
 33  │  ・CheckAndStack(V, H + 1)
 34  ■
 35  ・Return                                  /* 処理を終了 */
 36
 37  ○副プログラム: CheckAndStack(整数型: Vt, 整数型: Ht)
 38  ▲ Image[Vt, Ht] = CC                    /* 同じ色の領域内か? */
 39  │  ・Image[Vt, Ht] ← NC
 40  │  ・More ← More + 1
 41  │  ・VPos[More] ← Vt
 42  │  ・HPos[More] ← Ht
 43  ▼
 44  ・Return                                  /* 呼出し元へ戻る。*/

設問

次の記述中の【 】内に入れる正しい答えを,解答群の中から選べ。

このプログラムに関する先輩技術者(以下,先輩という)と新人技術者(以下,新人という)の会話である。

先輩:プログラムの動作を理解するには,処理の流れを追跡してみることが大切です。まず,画素の色がどのような順序で塗り替えられていくか,図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の値は一定値以下であるが処理が無限にループする。

Show answer

解答

  • a:
  • b:ウ(配列Imageの各添字の範囲チェックを省略できる)
  • c:イ(2(m+n))
  • d:イ(Wall ← NC)
  • e:ア(仕様どおりに同じ色で塗り替えて正しく終了する)
  • f:オ(変数Moreの値は一定値以下であるが処理が無限にループする)

解説

a(塗り替えの順序)

時間はかかるが、VS=5, HS=3 の画素を開始点として、プログラムを実際に追っていく。

まず、L25で CheckAndStack(5,3) が呼び出され、この時点で [5,3] の位置に色NCが設定され、この時点で【処理待ち画素の位置情報】が以下の様に更新される。

VPos[0] = 5、HPos[0] = 3、More = 1

その後に、L26~L34のループが、処理待ちの画素が無くなるまで繰り返される。
ループ開始時点で、一旦Moreの値を-1したうえで、【処理待ち画素の位置情報】の最後の要素を起点に、上→左→下→右の順に CheckAndStack() を呼び出して、チェックと色の塗り替えが行うロジックとなっている。

なので、L26~L34のループの1回目の時点では、VPos[0] = 5、HPos[0] = 3がそれぞれ最終要素となっているため、[5,3]を起点に上→左→下→右の順に CheckAndStack() を呼び出し、それぞれ以下のような結果となる。

  1. CheckAndStack(4,3)【起点の上のセル】
    → [4,3]の位置は、現在色と同じなので色が変わり、以下のように【処理待ち画素の位置情報】が変わる。
    VPos[1] = 4、HPos[1] = 3、More = 1
  2. CheckAndStack(5,2)【起点の左のセル】
    → [5,2]の位置は、現在色と同じなので色が変わり、以下のように【処理待ち画素の位置情報】が変わる。
    VPos[2] = 5、HPos[2] = 2、More = 2
  3. CheckAndStack(6,3)【起点の下のセル】
    → [6,3]の位置は、現在色と異なるので【処理待ち画素の位置情報】は更新されない。
  4. CheckAndStack(5,4)【起点の右のセル】
    → [6,3]の位置は、現在色と異なるので【処理待ち画素の位置情報】は更新されない。

この時点で、最初の3つが塗り替えられる順番が判明し、[5,3] → [4,3] → [5,2] の順となっている。この時点で、この順番に当てはまる選択肢は のみに絞り込まれる。

b(外周を0にする理由)

外周(添字0や9)の要素に0(CCにはなり得ない値)を入れておくことで、CheckAndStack が隣接要素をチェックする際、配列の範囲外(0行や9行)でも自動的に「同色でない」と判定される。これにより「添字が1〜8の範囲内か」のチェックが不要になる。
→ ウ

c(外周要素数)

m×n 画素の場合、プログラムで用意する配列のサイズは (m+2)×(n+2) となり、外周要素数はそこから本来の画素数を引いた (m+2)(n+2) – m×n … となるところなのだが、本プログラムのロジックに注意が必要。

L16~L19、L20~L23 のループ部分が、1→8 までのループとなっており、四隅に当たる画素([0,0]、[0,9]、[9,0]、[9,9]の4か所)が処理の対象から外れていることに気づく必要がある。

要するに、実際の外周要素のうち、元の画素に隣接する範囲に対してしか処理を行っていないため、外周として処理されるがその数は、m+m+n+n = 2(m+n) ということになる。

(m+2)(n+2) – m×n – 4 という式も成り立つのだが、この式から正解の選択肢にたどり着くのはなかなか難しく、以下のような図で考えた方がイメージしやすい。

d(0〜255すべて使う場合のWall)

ポイントとしては、外周の画素が「塗り替え対象の画素とならない」ようなロジックを組む必要がある、という点。

「塗り替え対象の画素になるかどうか」に関わる要素としては、以下の2点がある。

  • L12 より、開始点の画素色が、塗り替え対象の色と同じかどうか。
    • 同じなら処理終了となる
  • L38 より、CheckAndStackの引数で指定された画素の色が、開始点の画素色と同じかどうか。
    • 同じなら塗り替え対象、異なればスキップ

このうち、外周の画素に関わる条件は、L38 の CheckAndStack の部分となり、そこで、誤って外周画素と開始点の画素の色が同じに設定されてしまうと、外周部分が塗り替え対象となってしまう。

これをふまえて、各選択肢を検討してみる。

  • ア:「・Wall ← CC」とすると、L38 の部分で確実に外周画素が塗り替え対象となってしまうためNG。
  • イ:「・Wall ← NC」の場合、一見 L38 の条件と結びつかないので、塗り替え対象になるかどうか不定に思えるが、この場合に L38 の条件をクリアして外周が塗り替えられるのは、「NC = CC」が成り立つ場合だけであり、この場合は L12 の時点でそもそもプログラムが終了している。そのため、今回のプログラムでの対応としては全く問題はない。
  • ウ:「・Wall ← 256 – CC」とすると、一見、Wall にCCと異なる値がセット出来て良さそうに見えるが、CC=128 の場合に、Wallも128となってしまい、この場合は ア と同じ状態になるので、NG。
  • エ:「・Wall ← 256 – NC」とした場合、NCとCCの組み合わせ次第で、Wall と CC が同じ値になるケースが発生し、 ア と同じ状態になるのでNG。
    具体的には、CC+NC=256 になるような組み合わせはすべてNG
    例えば、CC=1 、NC=255 の場合、256 – NC = 1 で CC と同じ値となる。

e(1画素を同色で塗り替える場合)

L12〜14を削除して、プログラムを実行すると以下のようなフローとなる。

  1. L25のCheckAndStack呼び出しで、開始点の画素が元の色と同じ色で塗り替えられる。
  2. L26~L34のループに入り、開始点の上下左右各画素に対して、CheckAndStackが実行されるが、塗り替え対象となる画素は無く、ループ1回終了した時点で、L26のループ条件を満たさなくなり、処理終了。

最終的に、開始点の画素だけ塗り替えられる結果となり、本来の仕様通りの結果となる。→ ア が正しい。

f(2画素を同色で塗り替える場合)

L12〜14を削除して、プログラムを実行すると以下のようなフローとなる。

  1. L25のCheckAndStack呼び出しで、開始点の画素が元の色と同じ色で塗り替えられる。
  2. L26~L34のループに入り、開始点の上下左右各画素に対して、CheckAndStackが実行される。
    その結果、開始点の右隣りの画素に対して元の色と同じ色で塗り替えが実行され、【処理待ち画素の位置情報】の最後の要素に、開始点の右隣りの画素がセットされる。
    なお、この時点で More = 1 となっている。
  3. L26~L34のループが再度実行され、【開始点の右隣りの画素】を起点に、上下左右各画素に対して、CheckAndStackが実行される。
    その結果、【開始点の右隣りの画素】の左隣りの画素=元々の開始点に対して元の色と同じ色で塗り替えが実行され、【処理待ち画素の位置情報】の最後の要素に、元々の開始点の画素がセットされる。
    なお、この時点で More = 1 となっている。
  4. L26~L34のループが再度実行され、2. と同じことが起こる。
  5. L26~L34のループが再度実行され、3. と同じことが起こる。

ということで、L12~14のチェック処理を外すと、More = 1 のまま、いつまでたっても処理が終わらない、無限ループの状態に陥る。つまり、 が正解となる。

ちなみに、問題で結果が提示されている、③の「3画素からなる領域」の場合も、基本的な流れは上に示した無限ループのケースと大差ないが、2. のステップで More = 2 となる(Moreの値が2増える)点が異なる。

そのため、無限ループしていることには変わりないが、2. のステップを通るたびに More の値が増えていき、そうなると VPos[]、HPos[] の添え字の上限である64を超えることになるので、プログラムの動作結果としては、②と③では、違う結果となる。