12ヶ月の中の複数月の平均を求めるアルゴリズム


お世話になります。

業務で、今度の四月から開始される『働き方改革』の中に、複数月の平均が80時間を超えてはならないと  
いうのがあり、それを求めるためのツールをAccessで作成しています。

四月から始まり、三月で終わる一年の期間の中で、二ヶ月以上の連続した組み合わせ(4-5,4-5-6,4-5-6-7～1-2-3,2-3まで)の平均を算出するのですが、数を数えてみると合計で66パターンの組み合わせができてしまいます。これを人数分だけ計算するとなると、かなりの時間がかかると思います。  
勿論、一つ一つ行って、一度でも80時間超えがあれば、そこで確認済みにすれば良い話ではあるのですが、これをもっと効率的にやりたいと思っています。

上記のような、『総当たりの平均』を求めるやり方で、もっと効率の良い方法はありますでしょうか？SQLなどでできれば、とてもエレガントだとは思いますが…。SQLの平均の記述が解らないのではなく、コードのようにループさせなくて済む方法です。

強引にコードに直すと、下記のようになると思います。

[code]

    　　　Dim arr(11) As Long　'　ここでは宣言しかしていませんが、既に中身があるものと思ってください。
    　　　Dim d0 As Long, d1 As Long, d2 As Long
        Dim val As Double
        Dim flg As Boolean
    
        flg = False
        For d0 = 0 To 11 - 1
            For d1 = d0 + 1 To 12 - 1
                val = 0#
                For d2 = d0 To d1
                    val = val + arr(d2)
                    If (val / ((d1 - d0) + 1) > 80) Then
                        flg = True
                        GoTo End_for
                    End If
                Next
            Next
        Next
    
    End_for:
    
[/code]

よろしくお願いいたします。




『働き方改革』については、[時間外労働の上限規制の「2~6ヵ月平均で80時間以内」とは？【労働基準法改正
2019】](http://ttps://www.ieyasu.co/media/max_80h-average/) の記事を参考にしました。

この記事によると、「複数月の平均が80時間を超えてはならない」というのは正確には「2ヵ月ないし6か月平均で80時間以内」ということで、  
その意味は、“2ヵ月、3ヵ月、4ヵ月、5ヵ月、6か月のいずれの期間においても、月平均80時間以内にしなければならない”。

そうすると、平均を計算しないといけないパターンは、以下の４５種類  
２か月：１１パターン（４月から、５月から、・・・、２月から）  
３か月：１０パターン（４月から、５月から、・・・、１月から）  
４か月：９パターン（４月から、５月から、・・・、１２月から）  
５か月：８パターン（４月から、５月から、・・・、１１月から）  
６か月：７パターン（４月から、５月から、・・・、１０月から）

月の時間外労働時間が80時間を超えているかどうかの判断にも計算時間がかかるので、80時間を超えるケースが見つかるまで、全てのパターンを順に計算してみる以下のような愚直なコードのほうが計算時間は短くなると思います。

[code]

    Dim overtime(12) As Double　'　12か月(４月から３月まで）の時間外労働時間の配列（データは事前に入れられていると想定)
    Dim numOfMonth as Integer, startMonth as Integer, ov as Integer
    Dim val As Double
    Dim flg As Boolean
    
    flg = False
    For numOfMonth = 2 To 6  '平均をとる月の数を、２から６まで変えて調べる
        For startMonth = 0 to 12-numOfMonth '
            val = 0#
            For ov = startMonth To startMonth + numOfMonth -1
                val = val + overtime(ov)
            Next ov
            If ((val / numOfMonth) > 80) Then '月平均時間外労働時間が80時間超えか？
                flg = True
                GoTo End_for
            End If
        Next startMonth
    Next numOfMonth
    
    End_for:
      ' flagの値に基づいて、結果を表示する
    
[/code]




(面白そうなんで考えてみました。回答として妥当では無いと思うのですが、コメント欄には書ききれなそうだったので…他の方がこんな問題に対してどういうふうに考えられるのか興味あります。)

* * *

  * 連続する2ヶ月の平均が80時間超ならば、少なくともどちらかが80時間超 
    * (裏)連続する2ヶ月の平均が80時間以下ならば、少なくともどちらかが80時間以下

と

  * 連続する3ヶ月(m1,m2,m3)平均が80時間超で、かつ、その期間に含まれる連続する2ヶ月平均(※組み合わせは(m1,m2),(m2,m3)の2パターン)が全て80時間以下なら、端の月(期間の開始月m1、終了月m3、の2月)のいずれも80時間超

は正しそうで、ここから

  * 連続するnヶ月平均が80時間超で、かつ、その期間に含まれる連続するn-1ヶ月平均が全て(※組み合わせは2パターン)80時間以下なら、端の月のいずれも80時間超

も言えそうな気がするので

  1. 80時間超の月と前月との2ヶ月平均
  2. 80時間超の月と翌月との2ヶ月平均
  3. 80時間超の月と、翌直近の80時間超の月との間の平均

を調べれば良さそうに思われます。

単月での80時間超は許容される、というのが3.以外に1.,2.も調べないといけないのに繋がっているのかな、と。

