入出力
概要
競技プログラミングでは、標準入力から値を受け取り、計算した結果を標準出力に出す必要がある。
標準入力は、コマンドラインに打ち込んだ文字などの、外部からプログラムに指示を与える方法の $1$ つ。
競技プログラミングでは、問題の入力がこの標準入力から与えられる。
cin は、この標準入力から入力された情報を $1$ つ受け取り、変数に代入する。
ここでいう「$1$ つ」は、基本的には空白または改行までを指す。
標準出力は、コマンドラインへの文字での表示などの、外部に結果を伝える方法の $1$ つ。
競技プログラミングでは、計算結果をこの標準出力に提出しなければならない。
cout は、標準出力に指定内容を $1$ つ出力する。
標準エラー出力 cerr というものもあり、応用の項目で解説する。
正式にはそれぞれ std::cin、std::cout、std::cerr である。
ただし、通常はコード冒頭に using namespace std; を書いておけば、cin、cout、cerr だけで書ける。
コード例
整数型の入出力
int 型の場合。
long long 型も同様。
cout の後ろの << endl は改行を意味する。
同じ行にまだ続きを出力したい場合は不要。
int x;
cin >> x;
cout << x << endl;
小数型の入出力
double 型の場合。
下の例の場合、小数点以下 $12$ 桁まで出力。
fixed を付けなければ、全体で有効数字 $12$ 桁まで出力する。
また、fixed を付けない場合は特殊な数値表記で出力されて WA 判定されてしまうことがある。
競技プログラミングでは、基本的に小数を出力するときには fixed をつけること。
double d;
cin >> d;
cout << fixed << setprecision(12) << d << endl;
文字型の入出力
char 型の場合。
char c;
cin >> c;
cout << c << endl;
文字列型の入出力
string 型の場合。
string s;
cin >> s;
cout << s << endl;
動的配列の入出力
$N$ 要素の vector<int> の場合。
要素数を受け取るところから含めての入力。
int n;
cin >> n;
vector<int> a(n);
for (int i=0; i<n; i++) {
cin >> a.at(i);
}
$N$ 要素の vector<int> 型で、全部改行する場合の出力。
for (int i=0; i<n; i++) {
cout << a.at(i) << endl;
}
全部出すなら、範囲for文を使ってこんな記述でもよい。
for (auto i : a) {
cout << i << endl;
}
$N$ 要素の vector<int> 型で、空白区切りにして最後だけ改行する場合の出力。
for (int i=0; i<n; i++) {
cout << a.at(i);
if (i!=n-1) {
cout << " ";
}
}
cout << endl;
二次元配列の入出力
大きさ $H \times W$ の vector<vector<int>> の場合。
int h, w;
cin >> h >> w;
vector<vector<int>> a(h, vector<int>(w));
for (int i=0; i<h; i++) {
for (int j=0; j<w; j++) {
cin >> a.at(i).at(j);
}
}
for (int i=0; i<h; i++) {
for (int j=0; j<w; j++) {
cout << a.at(i).at(j);
if (j!=w-1) {
cout << " ";
}
}
cout << endl;
}
使い方の応用
入出力を高速化する
endl のところを '\n' にすると、動作が高速になる。
これは、endl が実際には改行した上でちゃんと画面に出すという処理だからである。
'\n' は改行だけする(出力予定データに入れるだけで、あとでまとめて出す)ので余計な処理がない。
ただし、プログラムが途中で異常終了したときに、どこまで実行されたのか分かりにくいことがある。
よほど大量に改行出力する場合以外は、endl にしておいた方がデバッグはしやすい。
また、C++では複数の入出力の方法があり、それらを混ぜて使用したときの誤動作を防ぐ機能がある。
しかし、cin と cout しか使わないのであれば、その機能は無駄に重いだけである。
main() の先頭に以下を記述することでその機能をオフにできるが、そこまで効果が大きいわけでもない。
ios::sync_with_stdio(false);
cin.tie(nullptr);
いくつもまとめて受け取る
cin や cout は、いくつもまとめて入出力できる。
例えば、int 型 $2$ つと string 型 $1$ つの場合。
int x, y;
string s;
cin >> x >> y >> s;
cout << x << " " << y << endl << s << endl;
vectorを並列で受け取る
$N$ 要素の vector<int> を $2$ つ使い、その配列 $2$ つの入力が
A[1] B[1]
A[2] B[2]
A[3] B[3]
...
となっている場合。
int n;
cin >> n;
vector<int> a(n), b(n);
for (int i=0; i<n; i++) {
cin >> a.at(i) >> b.at(i);
}
桁数を揃えて整数を出力する
cout << setfill('0') << right << setw(4) << x;
順に「足りない桁は 0 で埋める」「本体は右詰め」「$4$ 桁で」という指定。
時計形式で表示する方法は以下。
cout << setfill('0') << right << setw(2) << h << ":";
cout << setfill('0') << right << setw(2) << m << endl;
デバッグ出力:cerr
cerr は、cout とほぼ同じものと考えてよい。
本来はエラーメッセージ出力用なのだが、競プロの場合には別の活用方法がある。
解答は cout による出力のみで判定され、cerr による出力は解答の一部とは見なされない。
そのため、途中で確認用に変数の中身を表示させるコードは cerr で書くとよい。
それを残したまま提出しても基本的に AC 判定を出すことができる。
とはいえ、あまりに大量に cerr させると、その処理の時間のせいで TLE するリスクはある。
注意点
cinする個数や順序を間違えないようにする
cin が実行されると、まず受け取り待ち状態になる。
入力が $2$ つしかないのに $3$ 回 cin すると、$3$ 回目の入力待ちで停止状態になってしまう。
もしくは、入力の読み取りに失敗し、変数に意図しない何かが入ったまま実行されてしまう。
個数を間違えないこと。
また、n a b の順で与えられるところ、うっかり
cin >> a >> b >> n;
のようにすると、中身がぐちゃぐちゃになってしまう。
問題をよく読んで、与えられる順番通りに受け取ること。
解答の最後に改行する
問題によっては、最後の改行がないと WA 判定になる場合がある(APG4Bなど)。
関連知識
テスト
cerr は、提出前に変数の中身や処理の途中経過を確認するために使える。
大量に出しすぎると実行時間に影響するため、必要な情報だけを出すこと。
string型
cin >> s では、空白または改行までの文字列を受け取る。
空白を含む行全体を受け取りたい場合は、別の方法が必要になる。