C++
 Computer >> コンピューター >  >> プログラミング >> C++

C++で通過する車のペアを数える方法

長さNの配列が与えられ、その中には0と1のみが含まれています。値1は西方向へ進む車を、値0は東方向へ進む車を表します。

車Aと車Bのペアが 0 <= A < B < N の条件を満たし、Aが東方向へ、Bが西方向へ進んでいる場合、そのペアを「通過する車」として1つとカウントします。つまり、0のインデックスが1のインデックスより小さい (0, 1) のペアを数えることになります。

具体例で確認しましょう。

入力 − arr[] = {1, 0, 1, 0, 1}

出力 − 通過する車のペア数: 3

説明 − 0のインデックスが1のインデックスより小さい (0, 1) のペアは、(arr[1], arr[2])、(arr[1], arr[4])、(arr[3], arr[4]) の3つです。

入力 − arr[] = {1, 0, 0, 0, 0}

出力 − 通過する車のペア数: 0

説明 − 0のインデックスが1のインデックスより小さい (0, 1) のペアは存在しません。

素朴なアプローチ(Naive Approach)

まずは2つのforループを使った素朴なアプローチです。配列を先頭から走査し、0に遭遇した時点で、その位置から配列の末尾まで再度走査を行い、1に遭遇するたびにカウントを増やしていきます。計算量はO(N²)となります。

  • 0と1を含む配列arr[]を用意します。

  • 関数count_cars(int arr[], int size)は、配列とその長さを引数として受け取り、通過する車のペア数を返します。

  • 初期カウントを0とします。

  • インデックスi=0からi<size-1まで配列を走査します。

  • arr[i]が0の場合、インデックスj=i+1からj<sizeまで再度配列を走査します。

  • arr[j]が1であれば、ペア(arr[i], arr[j])が(0, 1)かつi<jを満たすため、カウントを1増やします。

  • 最終的に合計カウントが得られます。

  • カウントを結果として返します。

効率的なアプローチ(Efficient Approach)

次に、計算量O(N)で解ける効率的なアプローチを紹介します。この方法では、配列を末尾から走査します。末尾から順に1の個数を数えていき、0に遭遇したタイミングで、それまでに数えた1の個数(変数temp)だけペアが成立することになります。

  • 0と1を含む配列arr[]を用意します。

  • 関数count_cars(int arr[], int size)は、配列とその長さを引数として受け取り、通過する車のペア数を返します。

  • 初期カウントを0、tempも0とします。

  • whileループを使い、size >= 1 の間、配列を末尾から走査します。

  • arr[size-1]が1の場合、これまでに見つけた1の個数を表す変数tempを増やします。

  • そうでなければ0です(temp個の1よりも小さいインデックスを持つ)。このとき成立するペア数はtempなので、count = count + temp とします。

  • 次の要素へ進むためにsizeを減らします。

  • 最終的に合計カウントが得られます。

  • カウントを結果として返します。

実装例(素朴なアプローチ)

#include<bits/stdc++.h>
using namespace std;
int count_cars(int arr[], int size){
   int count = 0;
   for (int i=0; i<size-1; i++){
      if(arr[i] == 0){
         for (int j=i+1; j<size; j++)
         if (arr[j]==1){
            count++;
         }
      }
   }
   return count;
}
int main(){
   int arr[] = {1, 1, 0, 0, 1};
   int size = sizeof(arr)/sizeof(arr[0]);
   cout<<"Count of passing car pairs are: "<<count_cars(arr, size);
   return 0;
}

出力

上記のコードを実行すると、以下の出力が得られます −

Count of passing car pairs are: 2

実装例(効率的なアプローチ)

#include<bits/stdc++.h>
using namespace std;
int count_cars(int arr[], int size){
   int count = 0;
   int temp = 0;
   while (size >= 1){
      if (arr[size-1] == 1){
         temp++;
      }
      else{
         count = count + temp;
      }
      size--;
   }
   return count;
}
int main(){
   int arr[] = {1, 1, 0, 1, 1};
   int size = sizeof(arr)/sizeof(arr[0]);
   cout<<"Count of passing car pairs are: "<<count_cars(arr, size);
   return 0;
}

出力

上記のコードを実行すると、以下の出力が得られます −

Count of passing car pairs are: 2

まとめ

素朴なアプローチでは二重ループにより時間計算量がO(N²)になりますが、末尾から走査する効率的なアプローチを使えば、1回の走査で済むためO(N)まで削減できます。データサイズが大きい場合は、後者の手法を選ぶことで大幅なパフォーマンス向上が期待できます。

  1. C++で配列内の「割り切れるペア」の数を数える方法

    本記事では、任意のサイズの整数型要素を持つ配列が与えられたとき、その中から「一方の要素がもう一方の要素を割り切れる」ようなペア(整除ペア)の総数を求める方法を解説します。 配列とは、同じ型の要素を固定サイズで連続的に格納できるデータ構造の一種です。複数のデータをまとめて管理するために使われますが、「同じ型の変数の集まり」と捉えたほうが理解しやすい場合も多いでしょう。 具体例 入力:int arr[] = {1, 2, 3, 6} 出力:count is 4 説明:(1,2)、(1,3)、(1,6)、(3,6) の4つのペアにおいて、一方の要素が他方の要素を割り切れます。1はあらゆる整数を割り

  2. C++で車のフリート(車隊)の数を求める方法

    問題概要 同じ目的地に向かうN台の車が、片側1車線の道路を走行しているとします。目的地までは「target」マイル離れており、各車iは一定の速度speed[i](マイル毎時)を持ち、出発時点での位置は目的地からposition[i]マイル手前にあります。 車は前方の車を追い越すことはできませんが、追いついてバンパー同士をくっつけたまま同じ速度で走ることは可能です。このとき2台の車間距離は無視され、同じ位置にいるものとみなされます。車のフリート(車隊)とは、同じ位置・同じ速度で走行する1台以上の車の集合のことです。仮にある車が目的地ちょうどの地点でフリートに追いついた場合も、その車はそのフリート