👌

2つのコードのうち、どっちがよいコードなのかわからなくなったので、記事にしたが自己解決した

に公開

int count_report_num(vector<vector<int>> & children, int x){

    int mytask = 1;
    if(children.at(x).size() == 0){

        return mytask;
    }


    int sum = 0;
    for(int c: children.at(x)){
        sum+= count_report_num(children,c);

    }
    sum+=mytask;//自分の分も足す
    return sum;

}



int count_report_num(vector<vector<int>> & children,int x){
    int mytask = 1;
    int sum = mytask;
    if(children.at(x).size() == 0){

        return mytask; //sumかどっちがいいだろうか
    }

    for(int c: children.at(x)){
        sum+= count_report_num(children,c);
    }
    
    return sum;

}

このコードは、atcoderの演習問題で、再帰をしてみましょうというものの一部について、二つの書き方をしてみたもの。

https://atcoder.jp/contests/apg4b/tasks/APG4b_cc

グラフになっているので、子要素を特定し、呼び出して最終的な総数を答える問題。
6
0 0 1 1 4

親要素の番号が入力されて、各それぞれのノードについて、総数を出力する。

各インデックスにおけるそのグラフの大きさを求める問題。

子二つのグラフだったら3
みたいな。

これを、報告に見立てた問題として、演習問題が作成されている。

上は、元コードから、少し変えたもので、
sumの計算を終えた後に、自分自身の分を足し合わせている。

下は、最初に足し合わせている。

下のほうがいいコードな気がする一方で、最初に足したという情報を覚えておけるか心配になってきた。

小さい関数だからいいものの、大きい関数になったときに、
上の書き方のほうが良い気がしている。

使わない段階でsumを定義していることがあまりよくなさそうである。

int count_report_num(vector<vector<int>> & children,int x){
    int mytask = 1;
    
    if(children.at(x).size() == 0){

        return mytask;
    }
    int sum = mytask;
    for(int c: children.at(x)){
        sum+= count_report_num(children,c);
    }
    
    return sum;
}

こうすると、mytaskに何が入っているかわかりにくいか。

Atcoderに掲示されていたテストコードが一番いいコードでした。

以下テスト用コードに書かれていたものを引用。

// x番の組織が親組織に提出する枚数を返す
// childrenは組織の関係を表す2次元配列(参照渡し)
int count_report_num(vector<vector<int>> &children, int x) {
  // ベースケース
  if (children.at(x).size() == 0) {
    // 子組織から受け取ることは無いので1枚であることが確定している
    return 1;
  }
 
  // 再帰ステップ
  int sum = 0;
  for (int c : children.at(x)) {
    sum += count_report_num(children, c);
  }
  sum += 1;  // x番の組織の報告書の枚数(1枚)を足す
  return sum;
}

コメントによる補足が保守の観点でもよさそうです。

変数を安易に追加するのも危険だということを学べました。

https://atcoder.jp/contests/apg4b/tasks/APG4b_cc

Discussion