今回は競技プログラミングについてです。

解説動画はこちら



競技プログラミングの世界をのぞいてみよう


競技プログラミングとは

プログラミングを「速く・正確に・美しく」解く
頭脳スポーツです。

与えられるのは数行の問題文と、入力例
頭の中でアルゴリズムを組み立て
最速のコードで正答を競います。


競技プログラミングの概要

問題が与えられ、入力例と出力例も与えられます。

問題文から、入力を受け取って
出力例になるようなプログラムコードを書いていきます。

実際の競技では
プログラムコードが開催側のシステム内で実行されて
成否が出るような仕組みになっています。


問題文の例(超初級)

問題:最大値を求めよう

N 個の整数が与えられるので
その中で最大の値を出力してください。

入力例
5
10 3 5 8 2

出力例
10

サンプルコード
N = int(input())
nums = list(map(int, input().split()))
print(max(nums))

通常は計算量や、数値の上限などの制約が与えられます。

正解かどうかの判定は、もっと大掛かりな数値で自動計算されているようで
数が多い場合、制限時間に間に合わないことも有ります。



競技プログラミングの主な大会

AtCoder(日本)
Topcoder(海外)
その他も有るみたいだけど、色々休止中



競技プログラミングはどんなことに役立つのか

1.思考を“構造化”する力が身につく
問題を分解し、条件を抽象化し、最適なアルゴリズムを選ぶ
という一連の思考過程を繰り返し構造化思考力を鍛えることができます

2.アルゴリズムの理解が“AIを使いこなす力”になる
AIが生成したコードを見て
計算量のボトルネック、論理が最適化されているか
入力制約に対応できているか等を判断できます

3.「論理×直感」問題解決能力を鍛える最高のトレーニング
限られた時間と資源の中で最適な解決方法を
論理と直感、両方を磨きながら鍛えることができます

4.キャリアや採用で有利に働く
近年、大企業やスタートアップなどで評価される傾向
アルゴリズムが必要な企業への就職で有利になります




競技プログラミングの問題を解いてみよう


中級くらいの問題集、動画を止めて考えてみてね

問題1 : 文字列の入れ替えチェック(中級)

2つの文字列 S, T が与えられます
S の文字を並べ替えて T にできるなら Yes
できないなら No と出力してください

入力例
listen
silent

出力例
Yes

-------------------------------------------------------------


解説

文字の出現がすべて一致していればOK
sorted(S) == sorted(T) で判定可能です。

S = input().strip()
T = input().strip()
print("Yes" if sorted(S) == sorted(T) else "No")



問題2 : 数字の組み合わせの和(中上級)

N 個の整数が与えられます
この中から3つ選んで、その和が K になる組み合わせの数を求めてください

入力例
5 10
2 3 5 4 1

出力例
2

-------------------------------------------------------------


解説

単純に3重ループで解くコードの場合
3つの数値の和が K になれば OK です。

N, K = map(int, input().split())
A = list(map(int, input().split()))

count = 0
for i in range(N):
    for j in range(i+1, N):
        for k in range(j+1, N):
            if A[i] + A[j] + A[k] == K:
                count += 1
print(count)

ただし実際の競技では
3重ループだと、制限に合わない場合があるので
別の方法を検討することが多いようです。

ここでは一例として次のようなアルゴリズムで
解くこととします。

    1.  配列 A の要素をセット S にしておく(探索用)
    2.  二重ループで全ペア (i, j) を探索
    3.  そのペアの和 A[i] + A[j] を計算
    4.  target = K - (A[i] + A[j]) として、 S に存在すればカウント

これをコードに落とすと次のようになります。
# 入力
N, K = map(int, input().split())
A = list(map(int, input().split()))

# 集合(SET)を作成
S = set(A)
count = 0
seen = set()  # 同じ組み合わせの重複カウント防止用

for i in range(N):
    for j in range(i + 1, N):
        two_sum = A[i] + A[j]
        target = K - two_sum

        # 3つの値がすべて異なることを確認
        if target in S and target != A[i] and target != A[j]:
            # 組み合わせを小さい順にソートして一意化
            triple = tuple(sorted((A[i], A[j], target)))
            if triple not in seen:
                seen.add(triple)
                count += 1

print(count)






問題3 : 最短経路を求める迷路探索(上級)


H×W のマップが与えられ . は通行可
S から G までの最短距離を求めてください
到達できない場合は -1 を出力

入力例
4 5
S....
.###.
..#G.
.....

出力例
7


------------------------------------------


解説

BFS(幅優先探索 : Breadth First Search)で
最短距離を求めていきます。
(開始地点に近いノードから順に「横に広がるように」探していく手法)

入力は一旦省略し、直接データ化したコードです。
from collections import deque

data = """\
4 5
S....
.###.
..#G.
.....
"""

lines = data.strip().splitlines()
H, W = map(int, lines[0].split())
grid = [list(line) for line in lines[1:]]

# スタート(S)とゴール(G)を探して座標を求める
for i in range(H):
    for j in range(W):
        if grid[i][j] == "S":
            sx, sy = i, j
        if grid[i][j] == "G":
            gx, gy = i, j

# 4方向の移動ベクトルと距離配列の初期化
# dx,dyは上下左右の移動を表す、dist は各セルへの最短距離(始点からの距離)
# 訪問したら dist[nx][ny] = dist[x][y] + 1 と更新
dx = [1, -1, 0, 0]
dy = [0, 0, 1, -1]
dist = [[-1]*W for _ in range(H)]

# キュー初期化と始点の距離設定
# 始点をキューに入れて距離 0 をセット
# 以降はキューから取り出すごとに、そのセルから隣接を探索
q = deque()
q.append((sx, sy))
dist[sx][sy] = 0

# BFS のメインループ
# q.popleft() でキューの先頭から取り出し(FIFO)
# 4方向それぞれについて:
#	•	範囲チェック(境界外は無視)
#	•	壁 (#) なら通れないので無視
#	•	dist[nx][ny] == -1 は未訪問の確認(訪問済みならスキップ)
# 未訪問かつ通行可なら距離を +1 してキューに追加
while q:
    x, y = q.popleft()
    for k in range(4):
        nx, ny = x + dx[k], y + dy[k]
        if 0 <= nx < H and 0 <= ny < W:
            if grid[nx][ny] != "#" and dist[nx][ny] == -1:
                dist[nx][ny] = dist[x][y] + 1
                q.append((nx, ny))

# G に到達していれば dist[gx][gy] は非負の最短距離
#	到達していなければ -1(初期値)のまま出力される
print(dist[gx][gy])




まとめ

最適なアルゴリズムが必要な業務には
競技プログラミングの知識が役にたちます。

すごく時間の掛かる処理の高速化、省力化、消費電力低下など
実務面で有効な場面はかなり多いです。

若い人は就職面でも有利になるので、
競技プログラミングに取り組むのかかなりオススメです。