プログラミング入門 6. forループ

この記事は、下記プログラミング入門資料の一部です。

kenkoooo.hatenablog.com

for ループとは

forループとは、「N回繰り返し作業を行う」ということができるものです。

コードとしては以下のように書きます。

for (int i = 0; i < N; i++) {
    // ここに繰り返したい作業を書く
}

ややこしいですね。

for文の構造は

for ( ➀ ; ② ; ③ ) {
    // ここに繰り返したい作業を書く
}

において、以下のような実行内容や条件が含まれています。

  • ➀ 最初の繰り返しが始まる前に実行される内容。
    • 「int i = 0;」であれば「整数の入れ物iを作って、そこに0を入れる」となる。
  • ② 各繰り返しの前に確認する条件。この条件を満たしていない時は繰り返しを終了する。
    • 「i < N」であれば「iがNより小さい時」に実行されることになる。
  • ③ 各繰り返しの後に実行される内容。
    • 「i++」であれば「iに1を足す」が実行される。
    • 「iに1を足す」という操作は「i = i + 1」と表現されるが、これは非常によく使われるので省略して「i++」と書くことができる。
    • 同じように、「iから1を引く」という操作は「i = i - 1」と表現されるが、省略して「i--」と書くことができる。

つまり、

for (int i = 0; i < N; i++) {
    // ここに繰り返したい作業を書く
}

の場合は

  • ➀ 1番最初に、「整数の入れ物iを作って、そこに0を入れる」を実行する。
  • ② 条件「i < N」が満たされているなら、{ }内の処理を実行する。条件が満たされていなければ、終了する。
  • ③ { }内の処理が終わったら、「iに1を足す」を実行して、②に戻る。

という、繰り返しの処理を行うことが出来ます。

練習1

"Oyasumi"と10回表示してみましょう。

答え

for (int i = 0; i < 10; i++) {
    cout << "Oyasumi" << endl;
}

練習2

"Ohayo"と5回表示してみましょう。

答え

for (int i = 0; i < 5; i++) {
    cout << "Ohayo" << endl;
}

練習3

0から9までの10個の数字を順番に表示してみましょう。

答え

for (int i = 0; i < 10; i++) {
    cout << i << endl;
}

iはどんどん増えていくので、毎回iの中身を表示するだけで上手くいきます。

練習問題

arc037.contest.atcoder.jp

練習問題の解説

N回分の点数データをfor文で受け取って、それが80以上かどうか毎回調べ、80未満なら足りない分の点数を足していけば良さそうです。

#include <iostream>
using namespace std;
int main(void){
    // Here your code !
    
    int N;
    cin >> N;
    
    // 必要な点数の合計点をanswerに記録することにします。
    int answer = 0;
    
    // N 回繰り返すfor文です
    for (int i = 0; i < N; i++) {
        
        // i回目の点数をmに受け取ります。
        int m;
        cin >> m;
        
        // mが80未満なら足りない分だけ、つまり(80 - m)だけ勉強しなければならないので、
        // それをanswerに足しておきます
        if (m < 80) {
            answer = answer + (80 - m);
        }
    }
    
    cout << answer << endl;
}

練習問題2

abc015.contest.atcoder.jp

練習問題2の解説

小数点以下の切り上げにはceilというのを使います。これを使うために、先頭に

#include <cmath>

というのを追加しなければなりません。
追加後にコードの書き出しが

#include <cmath>
#include <iostream>
using namespace std;
int main(void){

のようになっていればOKです。

ceilを使うと小数点以下を切り上げてくれます。たとえば、

int a = ceil( 1.5 );

とすると、aには2が入ります。

これで問題を解くのに必要な知識が揃いました。
N個のバグデータをforで受け取って、バグの合計数を記録しておく必要があります。
また、バグ0の製品はスルーするので、バグの含まれた製品の数も記録しておきましょう。

#include <cmath>
#include <iostream>
using namespace std;
int main(void){
    // Here your code !
    
    int N;
    cin >> N;
    
    //バグを含んだ製品の数をbug_seihinに記録する。
    int bug_seihin = 0;
    
    //バグの合計数をbugsに記録する。
    int bugs = 0;
    
    // N個のバグデータを受け取るfor文
    for (int i = 0; i < N; i++) {
        
        // バグの数を受け取る
        int A;
        cin >> A;
        
        // Aが0より大きい時だけを考えれば良い
        if( A > 0 ) {
            //バグを含んだ製品の数が1増える
            bug_seihin++;
            
            //バグの合計数も加算する
            bugs = bugs + A;
        }
    }
    
    // 小数の入れ物heikinを作って、そこに平均バグ数を入れておく
    double heikin = (double) bugs / bug_seihin;
    
    // heikinの小数点以下を切り上げた数が答えになる
    int answer = ceil( heikin );
    
    cout << answer << endl;
}

余談

double heikin = bugs / bug_seihin;

double heikin = (double) bugs / bug_seihin;

で結果が変わります。

上の場合は bugs / bug_seihin を「整数として計算してから小数に変換して」heikinに入れています。「整数として計算してから」というのは「小数点以下を切り捨てて整数に直してから」ということになるので、正しくない値が入ることがあります。

下の場合は「小数として計算して」heikinに入れています。この方法なら望んだ結果が得られます。

クソ面倒ですね。

練習問題3

arc006.contest.atcoder.jp

練習問題3の解説

E[0]〜E[5]とL[0]〜L[5]を見比べる時に、

for (int i = 0; i < 6; i++) {
    for (int j = 0; j < 6; j++) {
        if (E[i] == L[j]) {
            atari++;
        }
    }
}

というように2重でforループを使えば、E[0]とL[0]、E[0]とL[1]、E[0]とL[2]、 …… 、E[5]とL[4]、E[5]とL[5]、を見比べることができる。

#include <cmath>
#include <iostream>
using namespace std;
int main(void){
    // Here your code !
    
    //当選番号の6つの数字を記録しておく
    int E[6];
    for (int i = 0; i < 6; i++) {
        cin >> E[i];
    }

    // ボーナス数字を記録しておく    
    int B;
    cin >> B;
    
    // 自分の数字を記録しておく
    int L[6];
    for (int i = 0; i < 6; i++) {
        cin >> L[i];
    }
    
    // 当選番号と一致した数をatariに記録する
    int atari = 0;

    // 当選番号のi番目と自分の数字のj番目を見比べて、同じならatariに1を足す
    for (int i = 0; i < 6; i++) {
        for (int j = 0; j < 6; j++) {
            if (E[i] == L[j]) {
                atari++;
            }
        }
    }
    
    // answerに当選順位を記録する
    int answer;
    
    // 6つ当たっていれば1等
    if (atari == 6) {
        answer = 1;
    } else if (atari == 5) {
        // 5つ当たっていれば3等
        answer = 3;
        
        //ただし、ボーナス数字が入っていれば2等になるので、
        //ボーナス数字と自分の数字を見比べる
        for (int i = 0; i < 6; i++) {
            if (L[i] == B) {
                answer = 2;
            }
        }
    } else if (atari == 4) {
        //4つ当たっていれば4等
        answer = 4;
    } else if (atari == 3) {
        //3つ当たっていれば5等
        answer = 5;
    } else {
        //それ以外ははずれなので0
        answer = 0;
    }
    
    cout << answer << endl;
}

練習問題4

code-festival-2014-qualb.contest.atcoder.jp

練習問題4の解説

for文で歩数データを受け取り、どんどん足していき、その合計がK以上になった時を出力すれば良さそうです。
合計がK以上になった後の歩数データは要らないので、そこでfor文を強制終了します。

for文を強制終了するときはfor文内でbreakをすると良いです。

breakの例

iがAよりも大きくなったら終了するfor文です。

for (int i = 0; i < N; i++) {
   if ( i > A ) {
      break;
   }
}

解答例は以下の通り。

#include <iostream>
using namespace std;
int main(void){
    int N;
    int K;
    
    cin >> N;
    cin >> K;

    // finishに目標達成日を記録する
    int finish;
    
    // i日目までの合計歩行数を記録する
    int sum = 0;
    for (int i = 0; i < N; i++) {
        // i日目の歩数データを受けとる
        int a;
        cin >> a;
        
        sum = sum + a;
        
        // i日目までの合計がK以上になったら、finishにその日付を記録して終了する
        if ( sum >= K ) {
            finish = i;
            
            // for文を強制終了できる
            break;
        }
    }
    
    // finishに記録されている日付は0日目から数えてi日目なので、1起点にする
    finish = finish + 1;
    
    //出力
    cout << finish << endl;
}

練習問題5

abc005.contest.atcoder.jp

練習問題5の解説

min(a, b);

とすると、aとbの小さい方が得られます。
これを利用して、上手く最小の時間を出してみましょう。

#include <iostream>
using namespace std;
int main(void){
    int N;
    
    cin >> N;
    
    // dekitateに一番出来たてのたこ焼きが何秒前に出来たかを入れます。
    // 最初はとりあえず最大値である100をいれます。
    int dekitate = 100;
    
    for (int i = 0; i < N; i++) {
        // i番目のたこ焼きが焼けた時間をTに受けとります
        int T;
        cin >> T;
        
        // dekitateとTの小さい方をdekitateに入れておきます
        dekitate = min(dekitate, T);
    }
    
    cout << dekitate << endl;
}