アルゴリズム講習会
講習会の目標
- C++を使って実践的なアルゴリズムを使えるようにする。
- ICPC国内予選のD問題までを解けるように!
第1回
C++
C++とは
- C++は、C言語に色々な機能を追加した言語。
- C言語と後方互換性がある。
- C言語で書いたプログラムはそのままC++で書いたプログラムとしても(ほぼ)動作する。
- 今までの講習会でもC++を使っていたが、実のところC言語の機能しか使っていなかった。
- とにかくできることが多い言語だが、その分とても難解。
- 講習会ではそんなに難しいことはしないつもりですが。
- ICPCでも最もよく使われている言語。
- Cより高機能で、Javaより高速なので。
- Cに比べ明らかにタイプ量が減るので、講習会でも今後はC++を使っていきます。
C++風にプログラムを書く
以下のプログラムは、標準入力で与えられた2つの整数の和を表示するC言語プログラム。
これをC++風に書いてみると、次のようになる。
主な違い
- 先頭の
#include
の辺りが変わっている。
- C++の標準入出力(
cin
とcout
)を使うにはiostream
をインクルードする。
using namespace std;
は標準の名前空間を使うという意味
scanf
がcin
に、printf
がcout
になっている。
cin >> (変数)
とすれば、変数に標準入力の内容が代入される。変数の型は自動で判別されるので、%d
とか%s
とか書かなくていい。
- ここでの
>>
と<<
は入出力演算子。cin
からデータが右に流れ出ていて、cout
へ向かってデータを左に流し込んでいくという感覚。
- 改行文字が
endl
になっている。
使い分け
多くの場合cin
・cout
を使ったほうが便利だけど、scanf
・printf
の方がいいときもある。
printf("%04d %2.4lf", 32, 7.3);
のように、桁数指定をするときとか。
scanf("%d,%d:%d", &a, &b, &c);
のように、入力が空白区切りでないときとか。
- 動作速度は
cin
よりscanf
の方が速い。
- 使い分けよう。
問題1
AIZU ONLINE JUDGEの問題10010「Simple Calculator」
cin
とcout
を使い、#include <stdio.h>
を使わずに解いてください。
標準ライブラリを使う
上の例では入出力が少し変わっただけだが、C++の標準ライブラリ(STLとも呼ばれる)を使うとコードを一気に簡略化できることもある。
C++の標準ライブラリには普段のプログラミングでよく使うツール(スタック、キュー、動的配列、文字列など)が事前に用意されている。
Cで作ったプログラムを標準ライブラリを使って簡略化
以下はコマンド入力を使ってスタックを操作するプログラム。去年のスタックの資料の解答そのまま。
これをC++標準ライブラリを使って書き換えると、以下のようになる。
- 自前でスタックを作っていた部分がなくなり、コードが30行ほど短くなった。
- 文字列を表すのにchar配列ではなくC++のstring型を使っているので、
==
による文字列比較ができるようになった。
- これは演算子オーバーロードというC++の機能の効果。
- 余談だが、等号演算子
=
もオーバーロードされているのでCでは意図通りに動かないstr = str2;
でも文字列の代入ができる。
- C++のコードのほうがより直観的なのがわかると思います。
よく使う標準ライブラリ
- vector:動的配列
- stack:スタック
- queue:キュー
- priority_queue:プライオリティキュー
- map:キーと値のペアの集合
- string:文字列
- algorithm:アルゴリズムつめあわせ
- sort:ソート
- find:値の検索
- lower_bound・upper_bound:2分探索
- min・max:最大最小
- next_permutation:順列
参考ページ
問題2
AIZU ONLINE JUDGEの問題13「Switching Railroad Cars」
標準ライブラリのstackを使って解いてください。以下にスタックの使い方例を載せています。
問題3
AIZU ONLINE JUDGEの問題1166「迷図と命ず」
2010年ICPC国内予選B問題。やや難しい。
以下にキューの使い方例を載せています。
次回やること(予定)
次回も引き続きC++をやる予定。内容は未定
内容案:
- STLの使い方
- vector
- map
- pair
- algorithm
- イテレータ
- structでクラス作成
- 演算子オーバーロード(大小比較可能なクラスを作る)
余談(defineマクロとか)
#include <....>
と毎回書くのは面倒なので、最初にテンプレを作っておくと便利。
こんな風に。
コーディング量を減らすため、include文のほかに色々なdefineマクロやtypedefを最初に書いている人もいる。
上記のテンプレでも#define rep(i,n)
なるものが定義されているが、これはfor文を略記するためのもの。
下記のように使える。
include・defineマクロやtypedefの使い方に決まった形式はなく、好みによっていろんなバリエーションのものが使われている(全然使われないこともある)。
Codeforcesで見つけた、include/define/typedefを多用しているコードの例:
個人的にはdefine/typedefを多用するのはそんなに好きではないけど、
実際便利なので他の人がコードを読んで無理なく理解できるレベルならどんどん使っていいと思う。
余談2(コンパイラについて)
Maximumの最初の講習会では、c++コンパイラとしてbcc(Borland C++ Compiler)を導入するようにしている。
しかし、各種プログラミングコンテストではg++(GNU C++ Compiler / gccのC++版)が使われることが多い。
bccとg++は基本的な部分ではほとんど変わりはないが、細かい違いがある。
特に重大なのが、64bit整数型(Javaで言うlong型)の扱いの違い。
上記のテンプレにはtypedef long long ll;
というものがあるが、これはbccではコンパイルエラーになる。
なぜなら、g++で64bit整数を表すlong long
型はbccでは使えないから。
bccではtypedef __int64 ll;
としないといけない。
これ以外にも、scanfやprintfでのlong値やdouble値の表現法が異なるなど、微妙な違いがある。
できればg++に統一したいところ。