0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

[アルゴ式] 再帰関数が配列のコピーを繰り返してしまい、時間切れになってしまったこと

Posted at

はじめに

最近、アルゴリズムの勉強として、アルゴ式に取り組んでいます。「アルゴリズム初級」の「再帰関数」に取り組んでいましたが、実装時に引っかかってしまったことがありました。初心者の大変初歩的なミスですが、メモがてら書き残しておきます。

引っかかった問題

部下の人数という問題です。

ある会社には N 人の社員がおり、0 から N−1 までの社員番号が振られています。
社員 0 以外の社員は自分より若い番号の社員のうち 1 人を直属の上司として持ちます。 社員 i の直属の上司は Piです。
社員 X は何人の部下を持つか答えるプログラムを作成してください。 ただし、「社員の部下の部下」のように直属でない部下も全て数えることとします。

image.png

グラフ構造を隣接リストで管理することにし、次のようなプログラムを書きました。

#include <bits/stdc++.h>
#define print(x) cout << x << endl;
#define rep(i, s, n) for (long long i = s; i < (long long)(n); i++)
#define INF 1010000000
using namespace std;
using ll = long long;

ll func(vector<vector<ll>> g, ll x)
{
  if (g[x].size() == 0) return 0;
  ll cnt = 0;
  rep (i, 0, g[x].size())
    cnt += func(g, g[x][i]);
  return cnt + g[x].size();
}

int main()
{
  ll N, X;
  cin >> N >> X;
  vector<vector<ll>> g(N);
  rep (i, 1, N)
  {
    ll p;
    cin >> p;
    g[p].push_back(i);
  }
  print(func(g, X));
  return 0;
}

サンプルケースは問題なく通過しましたが、一つのケースだけ「時間切れ」となってしまいました。

何が原因だったか

原因は、再帰関数の引数にありました。

...
ll func(vector<vector<ll>> g, ll x) 
{
...

二次元配列をそのまま渡しているため、関数が再帰するたびに毎回配列のコピーが発生していました。入力数が小さい時なら問題ありませんでしたが、入力数が大きい場合、コピーで時間が取られてしまっていたのです。

解決策

二次元配列の参照だけ渡すようにしました。これで無駄な配列のコピーが削減され、時間内に通過するようになりました。

...
ll func(vector<vector<ll>> &g, ll x) 
{
...

終わりに

普段は意識していなかった配列のコピーにも、計算機のコストがしっかりとかかっているのだと改めて認識しました。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?