愛媛県宇和島市のパソコン教室&プログラミング教室 みんなのパソコン教室の代表松井です。
これからプログラミングを学ぼうと考えている方、すでに学んでいるけれど、なかなかプログラミングが書けるようにならない人にヒントとなるような”考え方”について触れてみました。
はじめに:抽象と具体を行き来できる人が仕組みを作る
皆さんは、抽象と具体という言葉を聞いたことがありますか?抽象と具体に関する様々な書式も出版されていて、日常生活でも、ビジネスにおいても重要なキーワードであると私は思ってます。
「抽象と具体」を意識できるようになると、ビジネスでも勉強でも、物事の仕組みを自分で作れるようになります。これは「モデル化」とも呼ばれます。
上流工程の仕事ができる人、あるいは問題解決が得意な人は、例外なくこの“抽象化と具体化の往復”が上手です。
逆に、抽象化が苦手な人は、具体的な指示がないと動けません。
説明を求めても、要点がぼやけた話や、逆に細部にばかりこだわる話しかできない。
これは単に「説明が下手」なのではなく、「抽象と具体の行き来」ができていないのです。
プログラミングにも通じる「抽象と具体」
実は、この力はプログラミングにもそのまま当てはまります。
どれだけ文法を学んでも、自分でプログラムが書けない人が多いのは、コードを書く以前の段階 ― つまり「抽象化と思考の整理」ができていないからです。
そこで、ある実際の問題を例に考えてみましょう。
例題:AtCoder Beginner Contest 419 C – King’s Summit
競技プログラミングAtcoderに出題された問題です。
AtCoder Beginner Contest 419 C – King’s Summit
問題文
10の9乗行 ×10の9乗列のグリッドがあり、このグリッドの上から i 番目、左から j 番目のマスをマス (i,j) と表記します。
グリッド上にはN 人の人がおり、はじめ i 人目の人はマス (R i,C i ) にいます。はじめ時刻は 0 であり、各人は、時刻 1,2,3,4,… に以下のような移動をすることができます。
その場に留まるか、8 近傍のマスに移動する。ただし、グリッドの外側に出ることはできない。
厳密には、現在いるマスをマス (i,j) としてマス (i−1,j−1),(i−1,j),(i−1,j+1),(i,j−1),(i,j),(i,j+1),(i+1,j−1),(i+1,j),(i+1,j+1) のうち存在するマスのいずれかに移動する。また、移動には時間がかからないものとする。
N 人の人が全員同じマスに集まる時刻として考えられる最小値を求めてください。
制約
1≤N≤2×10の5乗
1≤R i,Ci≤10の9乗
入力される値はすべて整数
この問題をそのまま愚直にシミュレーションしたら、絶対に解けないでしょう。
縦横10億マスのなかで最大20万人の動きをプログラミングで制御するなんて考えただけでぞっとします。
そこで、この問題を抽象化しながら解く方法を考えていきましょう。
Step1:自分の言葉で言い換える(=一次抽象化)
まずは問題を自分の言葉で説明します。
「縦10億×横10億のマスがあって、そこに最大20万人の人がバラバラに立っている。
みんなが上下左右・斜めに動ける。
全員が同じマスに集まる最短時間を求める。」
ここまで整理できると、問題の本質が少し見えてきます。
大事なのは「マス目の広さ」でも「人数」でもなく、“最も遠い人同士が出会うまでにかかる時間”です。
Step2:さらに抽象化する(=仮説を立てる)
この時点で、次のような仮説を立てられます。
「全員が集まる最短時間 =最も離れた2人が出会うまでの時間」
つまり、N人全員のうち、距離が一番離れている2人が出会えば、
その時点で全員が同じ場所に集まることができる ― という仮説です。
Step3:具体化していく(=数式・手順に落とす)
ここからは具体化のステップです。
- 縦方向(行)の中で一番離れている2人を探す
- 横方向(列)の中で一番離れている2人を探す
- その2つの距離のうち、大きい方を「最長距離」とする
- その最長距離を2で割った値が、出会うまでの最短時間
- 最長距離が奇数なら、2で割った値の小数点を切り上げる(+1する)
これで、「考え方」がアルゴリズムになり、プログラムとして表現できる段階に到達します。
Step4:コードに落とし込む(=実装)
n = int(input())
r, c = [], []
for _ in range(n):
ri, ci = map(int, input().split())
r.append(ri)
c.append(ci)
max_dist = max(max(r) - min(r), max(c) - min(c))
ans = max_dist // 2 if max_dist % 2 == 0 else max_dist // 2 + 1
print(ans)
この短いコードの裏には、
「抽象化 → 具体化 → 実装」という思考の流れが詰まっています。
人によってコードの書き方は変わってくるかもしれません。ただし、正しく抽象化→具体化できた問題は、どんなコードであれ正しい答えを導き出してくれるし、方針がぶれることはないと思います。もちろん正しい文法(コンピュータが認識できる書き方)で書かれているということは必須ですが。
コードの書き方・解説については、省略します。また、実際にatcoderの問題を解くためにはプログラムの計算量というのも考慮しながら、設計していく必要があるのですが、今回は、具体と抽象の話をメインにしていますので省略します。
まとめ:抽象化は問題をシンプルにまとめながら仮説を立てる力
抽象化とは、物事をシンプルにまとめること。
同時に、「本質的な課題は何か?」を見抜く力でもあります。
一方で、具体化とは、抽象的な仮説を現実の形に落とし込むこと。
プログラミング言語はその具体化のための“道具”に過ぎません。
抽象と具体を行き来できる人は、
プログラミングでもビジネスでも、ゼロから仕組みを作ることができます。
だからこそ、プログラミングの学びは「文法」よりもまず、
考える力を鍛えることが大切なのです。