競技プログラミングの勉強会を開催している話
ソフトウェアエンジニアの尾崎です。今年の6月頃から趣味で競技プログラミングに取り組んでいます。最近はカブクオフィスの会議室を借りて競技プログラミングの勉強会を開催するようになったので今日は競技プログラミングの紹介と勉強会の宣伝をしようと思います。
TL;DR
- 競技プログラミングはオンラインで気軽に参加できて楽しいです。
- 競技プログラミングで培った知識や思考力は仕事で役に立つかもしれません。
- カブクオフィスにて競技プログラミング初級者向けの勉強会を開催しています。
競技プログラミングのこと
まずは競技プログラミングについて簡単に紹介します。
概説
競技プログラミングは与えられた課題に対して参加者がプログラムの形で解答し
- 解答プログラムを作成する速さ
- 解答の計算量の少なさ
- 解答の使用メモリの少なさ
など定量的な基準のもとで優劣を競うものです。
オンラインジャッジ
オンラインジャッジとは文字通りオンラインで解答をジャッジする仕組みで、競技プログラミングを支える重要な技術です。一定の正解が存在するタイプの問題であれば、開催者は入力と出力の組み合わせからなるテストケースをサーバ上に用意しておきます。そして、参加者がアップロードした解答プログラムが全てのテストケースを満たすかどうかを判定して成否を返します。このように解答プログラムの成否判定を自動化することで、大勢の参加者が同時に同じ課題に挑戦することが可能になっています。また、オンラインジャッジを提供しているサービスの多くは過去の問題もオンラインジャッジ可能な状態で公開しているので、過去問にも気軽に挑戦することができます。
面白い例題
競技プログラミングを説明する際によく用いられる面白い問題があるので紹介します。この問題は北京大学が運営しているPOJというオンラインジャッジサービスに掲載されています。競技プログラミングの参考書として有名なプログラミングコンテストチャレンジブック^1の冒頭にも掲載されています。
Ants^2 (以下問題文和訳)
長さL cmの水平な柱の上をn匹の蟻たちが秒間 1 cmの速度で歩いています。蟻は柱の終点に到達すると即座に落下します。また、2匹の蟻が出会うと彼らは即座に反転して歩き始めます。(この手の問題のお約束ですが蟻の大きさは考慮しません。)初期状態でのn匹の蟻の位置(柱の左端からの距離x[1], x[2], x[3]…x[n])が与えられますが、蟻がどちらに向かって歩いているかはわかりません。この条件で、全ての蟻が柱から落下するまでにかかる時間の最小値と最大値を求めてください。
問題のイメージ図
一見するとそれぞれの蟻が左を向いている場合、右を向いている場合の全ての組み合わせでの所要時間を計算して最小値と最大値を求めなければならないように見えます。こうすると蟻の数nに対して2^n通りの場合を検証しなければならないため計算に莫大な時間がかかってしまいます。しかし、あることに気づくととても簡単に問題を解くことができます。ぜひ解法を考えてみてください。(スクロールすると解説に続きます。)
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
解説です。個々の蟻を識別する必要はないので、「蟻同士が出会って反転する」という挙動は「出会った蟻同士がそのまま真っ直ぐ進み続ける」という挙動に読み替えることができます。
解説のイメージ図
こうすれば簡単です。それぞれの蟻について右向きのときと左向きのときの落下するまでの時間を簡単に計算することができます。それぞれの蟻がより短い時間で落下する向きでの落下までの時間を計算して、その中の最大値を求めれば最小時間を得ることができます。同様にして最大時間も導出できます。擬似コードでは下記のようになります。
// 変数宣言
int n, L;
array<int> antPositions;
// 標準入力を受付(下記のような入力を想定)
// n, L
// x[1], x[2], x[3]...x[n]
input >> n;
input >> L;
repeat(n) {
int x;
input >> x;
antPositions.push(x)
}
// それぞれの蟻について落下までの時間がより短(長)い向きの時間を導出して、その中の最大(小 )値を取得
int minTime = antPositions.map(position => min(position, L - position)).getMax();
int maxTime = antPositions.map(position => max(position, L - position)).getMin();
// 標準出力
output << minTime << endLine;
output << maxTime << endLine;
このように解法を閃けば簡単に解ける問題もあり、一方でアルゴリズムの知識を要求されるような問題もあります。競技プログラミングではいろいろな問題に挑戦しながら発想力を鍛え、アルゴリズムの知識を深めることができます。
はじめるには
競技プログラミングを始めるにはAtCoder^3というサービスがおすすめです。理由は国内のサービスでかつ参加者が多いこと、初学者向けのガイド^4が充実していること、初級者向け競技の開催があり参入障壁が低いことです。 AtCoderでは週末にオンライン参加型の競技が開催されていて、参加者は2時間前後の制限時間で4つから6つの問題に取り組みます。使用できる言語も多様で競技プログラミングの世界で定番のC++やJava, Pythonを始めとしてRustやGoといった新し目の言語でもコードを投稿することができます。
勉強会のこと
ここまでで競技プログラミングの概要を紹介したのでここからはカブクオフィスで開催している勉強会について紹介します。大前提として私自身が競技プログラミングを始めたばっかりの初級者なので初級者を対象にした勉強会を開催しています。
勉強会を開く理由
オンラインで参加できる競技プログラミングのオフライン勉強会を開いているのには理由があります。一つは、せっかく競技プログラミングという面白くて勉強になるコンテンツに取り組み始めたので私自身が長く続けてたいと考えていることです。オフラインのコミュニティを構築すればそれ自体が競技プログラミングのモチベーション向上に寄与すると考えています。もう一つの理由は、他の人のものの考え方を知りたいということです。アルゴリズムを勉強することと比べて問題文をアルゴリズムに落とし込んでいく能力を鍛えるのは少し難しそうです。勉強会では特に後者にフォーカスして解法にたどり着くプロセスを共有しながら問題を解いていきたいと考えています。
これまでの勉強会
これまでに勉強会を2回開催しています。^5
1回目
初回の勉強会は人づてに競技プログラマを集めて開催しました。また、取り組む問題のジャンルを組み合わせ問題に絞りました。最初に組み合わせ問題に頻出なアルゴリズムについて簡単な解説を実施し、事前に作成した擬似的なコンテストを解き進めていきました。結論から言うと主催側の勉強が不足していてアルゴリズムの解説に片手落ち感がありました。そのかわり参加者の積極的な意見交換が生まれて学べることは多かったです。問題を解き進めていく段階でも意見交換が活発でいろいろな問題の捉え方を知ることができました。ただ、疑似コンテストを小さく複数セットに区切ってしまったことが裏目に出て特定の問題の解法を思いついたかどうかで進度に大きな差が生まれてしまいました。ジャンルを固定することは良かったので問題点を改善しつつこの方針で次回も開催しようと考えました。
2回目
2回目の開催では参加者をWEBページから公募しました。その結果WEBやSNSを見て興味を持ってくださった競技プログラマが新規に2人参加してくれました。また、前回の反省を活かして初頭の解説を拡充し、時間いっぱいで一つの疑似コンテストを進めていく方針に切り替えました。結果は良好で、比較的ゆったりと一つの疑似コンテストに取り組んでいくことができました。問題点を上げるとすれば、2回目のジャンルとして指定したグラフ理論の問題は実装が難しいものが多く、前回よりも少し難易度が高かったです。
今後の予定
ある程度開催方針が固まったので今後も継続的に勉強会を開催していく予定です。月一ペースでおそらく土曜日のお昼頃から開催します。開催時はCompassのイベントページ[^5]から告知するので、興味がある方がいれば気軽にイベントメンバーに登録しておいていただけると嬉しいです。
おわりに
最後まで記事を読んでいただいてありがとうございます。競技プログラミングはオンラインで気軽に参加できるものなのでぜひ一度遊んでみてください。また、勉強会に興味を持ってくださった方がいらっしゃったら是非勉強会に遊びに来てください。カブクから飲料とお茶菓子の無償提供もあります。最後に、カブクでは趣味で競技プログラミングに取り組んでいるような知的好奇心旺盛なエンジニアを絶賛採用中なので是非ご応募ください。
その他の記事
Other Articles
関連職種
Recruit