輪郭をなぞるだけのブログ

浅学菲才のためにおそらく嘘も多い

getline 関数で標準入力を受け取る

追記 (2020/11/26)

https://codeforces.com/contest/1279/problem/D
参照した問題は多分これなんだけど、全然いらなかったし、むしろ下記の受け取り方だとおかしい。
そうは言っても、getline での受け取り方は知っておいた方がいいと思うので、残しておく。

本文

競プロの大抵の標準入力は、cin で済ませられる (?) 。
ただ、要素数の指定がない場合はこうもいかないので、別の方法を取る。

例えば、以下のような手順でできる。

  1. まず、getline 関数で空白と改行を含んだ1行の文字列 (string) を受け取る。
  2. 受け取った文字列を文字列ストリーム (stringstream) に入れる。
  3. 文字列ストリームの中身がなくなるまで、要素を読み込む。(判定条件 : eof)

ただ、cin を使ったあとにこの操作をしてしまうと、思ったように動いてくれない。
上記の 1~3 の前に以下の操作をしておくと解決した。

  • cin のメンバ関数には、ストリームから文字を入力して捨てる ignore 関数があり、これを作用させて、改行文字をスキップ (?) させる。

もしくは

  • 入力受け取りを getline で統一する。

cin だと改行文字まで読み込まれずに、次の読み込みが改行文字からになってしまうが、getline だと改行文字まで読み込まれて、次の読み込みが次の行からになるといった感じだろうか。

昨日の Codeforces の問題では、以下のように、リストの個数のみが与えられ、それに続いて、リストが与えられるという形式であった。
5
2 1 2
2 3 1
3 2 4 3
2 1 4
3 4 3 2

cin.ignore() を使用した以下のソースコードを実行すると、入力は正しく受け取られていることが確認できる。

#include <iostream>
#include <vector>
#include <string>
#include <sstream>
using namespace std;

int main(){
    int n;
    cin >> n;
    cin.ignore();   // 改行文字をスキップ
    
    vector<vector<int>> a(n);
    string s;   // 入力を受け取るための文字列変数を用意しておく
    for(int i = 0; i < n; ++i){
        getline(cin, s);
        stringstream ss(s);
        int tmp;    // 文字列ストリームから読み込んだ数字を一時的に保存
        while(!ss.eof()){   // 改行文字を読み込むまで実行
            ss >> tmp;
            a[i].push_back(tmp);
        }
    }
}


【雑記】
cin がクラスであることを初めて知った。
いつも通りここに書いてあることが本当かは分からない。
一時期 stringstream 書いていたが、よく分からずに写経していただけなので、全然身に付いてなくて悲しい。

今日は楽しみにしていたイベントがめちゃくちゃおもしろくて満足していたが、AGC でへし折られて悲しい。