LED通信事業プロジェクト エンジニアブログ
【小ネタ】共テ「情報Ⅰ」第三問をF#で書いてみる
記事更新日 2025年1月28日
はじめに
先日の1月18、19日に大学入学共通テストが行われました。実は、今年2025年から、大学入学共通テストに「情報Ⅰ」という科目が加わったんですよね。大学入学共通テスト、通称”共テ”は、古くは共通一次、センター試験と呼ばれていたもので、もともとは国立大学の一次試験の位置付けでしたが、徐々に共テを選択して入学できる私立大学が増え、最近では早稲田大学の政治経済学部が国立大学と同じように共テ受験を必須にする※1など、共テは私立専願であっても受験しなければならないテストになりつつあります。
共テは、共通一次以来これまで何十年も“英国数理社※2”の5教科で行われてきましたが、今回ついに新しい教科が追加され”英国数理社情”の6教科になりました。大げさかも知れませんが、今年は大学受験史上歴史的な年と言えるのではないでしょうか。
さて、昨今の受験事情に疎い人(主に私と同じおじさん)のために「情報」という教科を説明しておきます。20世紀末、インターネットや携帯電話の普及により、「情報」という学問に対する必要性が社会的に高まり、その結果、2003年から高校で「情報」という授業がスタートしました。その辺りは、おじさんでも把握されているでしょう。で、「情報」が具体的に何をする学問かというと、学習内容としては結構幅が広くて、例えば、
- 情報テクノロジー
- 情報セキュリティ
- データベース
- プログラミング
- コンテンツデザイン
の様な内容を勉強するようです(おじさんの時代には無かったので詳しくは知りません)。「情報」=プログラミングと思われるおじさんも多いかと思いますが、実はプログラミングは、比較的最近に追加された内容であり、もともとは情報のまとめ方とか、セキュリティやデータベースとか、そういったことを学習する教科だったようです。現在は「情報Ⅰ」が必須で、より高度な「情報Ⅱ」が選択となっています。そして、必須である「情報Ⅰ」が共テの1科目として、今年から加えられたという経緯となります。
通信業界という、情報界隈の片隅で食っている自分としては、こういった学問を高校で学ぶのはとても重要だと思いますし、特に全高校生が(ほんの少しでも良いので)「プログラミング」が出来るようにすべきだ、ぐらいまで思っておりますが、さりとて最近の受験事情に疎いおじさんとしては、「最初だし、情報を必須にする大学は少ないのかな?」と漠然と思っていました。しかし、蓋を開けると結構「情報Ⅰ」を必須にしている大学が多く、さらに、東京大学を筆頭に、理科や社会(の1科目)と同配点の大学も多いようです。つまり、共テにおいて情報は物理や世界史と同じ価値ということです。それどころか、情報系等の一部の学部学科では、この情報Ⅰの配点を大きくしているところすら存在します。
テストの中身についてですが、初回である今回の共通テスト「情報Ⅰ」の問題は、4つの大問に分かれていて、その内の大問3(第三問)がプログラミング関連の問題でした。内容を見る限り、おそらく自分である程度プログラミングをしたことがあるという高校生なら、この大問3は時間をかけずに、容易に満点が取れる内容であったのではないかと予想されます。それ以外の大問も比較的容易であり、今年の「情報Ⅰ」は簡単すぎるのでは無いか?という声すら上がっているようです。実際、(中間発表時の)平均点も73.1点(100点満点)と、他教科よりかなり高くなっています。
さて、本題です。いきなり下衆で申し訳ないですが、F#の普及に努めるこのブログとして、この記念すべき1回目の「情報Ⅰ」の試験を無駄には出来きないんですよね。だって、今注目を浴びているであろう内容に乗っかることで、もしかしたらこれを機に興味を持ってくれる人がいるかもしれないじゃないですか。というわけで、今回のブログは「問題に出てきたプログラミング例をF#で実装したら、どうなるか?」という内容で書きたいと思います。2026年の共テ受験を予定している高2生は要チェックかも??
2025年 共テ「情報Ⅰ」第三問の要旨
今回取り上げる、「情報Ⅰ」の大問3である第三問は、プログラミングについての問題です。この大問3は、内容の割に結構文章が長い問題です。問題文全文を載せると誰も読んでくれないので、非常にコンパクトに要旨だけ説明します。実際の試験問題は予備校などのサイトでご確認下さい。
第三問超抜粋
作成する工芸品と作成にかかる日数は以下のようになっている。
工芸品 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|
作業日数 | 4 | 1 | 3 | 1 | 3 | 4 | 2 | 4 | 3 |
これを、次のルールで部員に割り振っていく。
最も早く秋になる部員(複数いる場合はその内最小の番号の部員)が、空きになった日付から次の工芸品を担当する。
部員が3人だった場合に、このルールを適用すると、下の図の様に部員へ工芸品が割り当てられる。
これを、プログラミングにより自動化せよ。
という問題です。全てを0からコーディングしろというのは、マークシートの試験問題として成り立たないので、前段の長い文章中やコードに穴があって、選択肢から選ぶという穴埋め問題となっております。
途中、段階はあるのですが、問題文に載っている最終的なコードは次のようになっています。(コードコメントは、筆者が勝手に付けたものです。)
(01) Nissu = [4, 1, 3, 1, 3, 4, 2, 4 ,3] // 工芸品毎にかかる日数
(02) kougeihinsu = 9 // 工芸品リストの長さ
(03) Akibi = [1, 1, 1] // 部員毎の空き日を格納するリスト
(04) buinsu = 3 // 部員数、すなわち空き日リストの長さ
// 工芸品の日数を追加していくループ
(05) ( ケ )を1から( コ )まで1ずつ増やしながら繰り返す:
(06) | tantou = 1 // Akibi[]の初期位置を設定
| // 空き日が最小のtantouを探すループ
(07) | buinを2からbuinsuまで1ずつ増やしながら繰り返す:
(08) | | もし( キ )ならば:
(09) | |_ |_ tantou = buin
| // 工芸品の担当部員が決定したので表示
(10) | 表示する("工芸品", kougeihin, " … ", "部員", tantou, " : "
| Akibi[tantou], "日目~"
| Akibi[tantou] + ( サ ), ”日目")
| // 担当部員の空き日に、工芸品の作業日数を追加
(11) |_ Akibi[tantou] = Akibi[tantou] + ( シ )
// 答え:
// ケ = kougeihin, コ = kougeihinsu
// キ = Akibi[buin] < Akibi[tantou]
// サ = Nissu[kougeihin] - 1
// シ = Nissu[kougeihin]
と、こんな感じです。こういう問題が出るんですよ、ってことをお伝えするために、敢えて問題の穴を残して掲載しています。皆さん、解けましたか?もちろん、実際の問題は、これ以前にいくつもの小問があって、徐々に誘導されていきますので、いきなりこのコードが出てくるわけではないんです。とは言え、普段からプログラミングされている方なら、いきなりこの穴あきコードを出されても正解できるんじゃないでしょうか?
F#で大問3のコードを書いてみよう
それでは、先ほどの10行ちょっとの簡単なコードをF#に書き換えます。なんでF#に書き換える必要があるのかって?いや、そういうネタなんで考えないで下さい・・・
まずは単純に、できるだけ、元のコードに合わせる形でF#に変換しています。
/// 情報Ⅰ第三問 F#によるコード(もとコードそのまま置き換え)
let Nissu = [|4; 1; 3; 1; 3; 4; 2; 4; 3|]
let kougeihinsu = 9
let Akibi = [|1; 1; 1|]
let buinsu = 3
// 工芸品毎のループ
for kougeihin = 1 to kougeihinsu do
let mutable tantou = 1 //mutable変数を使用
// 工芸品割り当てループ
for buin = 2 to buinsu do
if Akibi[buin - 1] < Akibi[tantou - 1] then
tantou <- buin
else ()
Console.WriteLine("工芸品" + kougeihin.ToString() + " … " +
"部員" + tantou.ToString() + " : " +
Akibi[tantou - 1].ToString() + "日目~" +
(Akibi[tantou - 1] + Nissu[kougeihin - 1] - 1).ToString() + "日目")
Akibi[tantou - 1] <- Akibi[tantou - 1] + Nissu[kougeihin - 1]
ざっと、こんな感じです。面倒ポイントはfor文。一般的なプログラミング言語の配列のインデックスって、0スタートなんですよね。この問題文は1からスタートになっているので、どこかで調整しないといけないんです。下の例では、なるべくオリジナルに近づけるよう、全ての配列インデックスを"-1"することで、0スタートの配列と整合を取っています。
次に、これを極めてF#ぽい書き方に変えるとどうでしょう?F#ぽさって、人によって異なるでしょうが、私の中では、以下がF#の特徴だと思っています。
- letによる変更不可(immutable)変数
- 再帰関数
さて、この2つの特長を活かして、コードを作り直してみます。
/// 情報Ⅰ第三問 F#によるコード(F#っぽい書き方)
// インプット部分(工芸品毎の日数と部員数)
let Nissu = [|4; 1; 3; 1; 3; 4; 2; 4; 3|]
let buinsu = 3 //部員数を先に宣言
let Akibi = Array.create buinsu 1 //部員数のサイズの配列を作る
// 工芸品割り当てを判断するフローを再帰関数に変更
let rec wariate (akibi:int[]) tantou buin =
if buin < (akibi.Length) then
if akibi[buin] < akibi[tantou] then
wariate akibi buin (buin + 1)
else
wariate akibi tantou (buin + 1)
else
tantou
// 工芸品毎のループ
for kougeihin = 0 to (Nissu.Length - 1) do
let tantou = wariate Akibi 0 1 //工芸品の割り当て
Console.WriteLine("工芸品" + (kougeihin + 1).ToString() + " … " +
"部員" + (tantou + 1).ToString() + " : " +
Akibi[tantou].ToString() + "日目~" +
(Akibi[tantou] + Nissu[kougeihin] - 1).ToString() + "日目")
Akibi[tantou] <- Akibi[tantou] + Nissu[kougeihin]
いかがでしょう?ちょっと長くなっちゃいましたね。先ほどのコードから、
- 配列の宣言方法を変えて汎用性を高くした
- "mutale"宣言をする変数を使わないようにした
- "mutable"変数を使わないために、for文を再帰関数にした
見た目はfor文の方が簡単ではありますが、全て関数にすることで副作用を最小限に抑えて、エラーになりにくいコードになっています。と、言い訳したところで、普通の人から見れば複雑になっただけのような気がしないでもありませんが、まあそれもF#だということで。
まとめ
今の話題に乗っかる形で、大学入学共通テストの「情報Ⅰ」のプログラミング問題を、をF#で再現してみました。まあ、F#はおまけで、今回は、皆さんに情報の試験というものを紹介、という意味合いの方が高かったですかね。
ところで、今回の問題の答えが全く分からなかったという社会人の方は、ちょっと焦った方が良いかも知れません。今回の「情報Ⅰ」がとても簡単だったということは、大学へ行くような高校生は、みんなこれぐらいの問題は簡単に解ける、ということを意味します。つまり、4年後(以降)に皆様の会社に入ってくる子達は、全員これぐらいのコードは書けるんですよ。やばいと思った、そこの方。これを機にプログラミングを勉強されることをお勧めします。AI時代でプログラミング不要説もありますが、現段階では、むしろプログラミングが理解できるからこそ、プログラミングでAIが活用できるという状況にあります。運が良いことに、今はAIに聞けば何でも答えてくれますから、プログラミング学習の敷居はとっても低いです。尚、もし今後プログラミングが勉強したくなって、どの言語から学ぶかを悩んだら、その際は是非F#も候補に入れて下さいね!
※1; 早稲田大学政治経済学部は、2021年の入試から、共通テスト+独自試験(二次試験)と方式を変えた。共テが英国数ⅠAの3科目必須、情報を含むその他から1科目選択で、1科目25点の合計100点満点、独自試験が100点満点、合計200点満点という配点である。私立文系最難関学部が数学を必須にしたため話題となっている。
※2; 英(英語)は、正確には「外国語」であり、2025年の共通テストでは、「英語」「フランス語」「ドイツ語」「中国語」「韓国語」の中から一つ選択。ただし、全ての試験で英語以外の言語が使用できるわけでは無く、例えば上記の早稲田大学政治経済学部だと、共テにおいて英語以外だとフランス語かドイツ語しか選択できない(中国語、韓国語は選択不可)。