[[20061002220044]] 『複数の数字の合計』(MATT) ページの最後に飛ぶ

[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]

 

『複数の数字の合計』(MATT)

 はじめまして。早速ですが以下の内容よろしくお願いします。
  近所のガソリンスタンドでこのような特典があります。
  「ガソリン150リットル分のレシートで500円の商品券プレゼント」
  そこで質問ですが、たまりにたまったレシートの給油量を入力し、150リットル以上で
  なおかつ、150リットルに限りなく近くなるレシートの組み合わせを計算式または関数
  で簡単に出来ないでしょうか?
  例えば、A**リットル、B**リットル、C**リットル、D**リットル、E**リットル、F**リットルの場合、
  A+C=151リットル、B+D=151.5リットルみたいな計算を簡単にしたいのです。
 うまく説明できませんが、よろしくお願いします。

  EXCEL2002
  WIN XPです。

 こんな関数はどうでっか?
 Alt+F11でVBEを開く
 「挿入」→「標準モジュール」を選択
 真新しいモジュールに下のコードをコピペ
 エクセルに戻り
    A	         B	    C	         D	    E
 1 85リットル  98リットル	69.5リットル  92リットル	70リットル
 2					
 3					
 と、まあ、こんな具合にデータを配置し、F1あたりに=matt(a1:e1)と入力してみて
 おくんなはれ。
 どうでっか、こんな塩梅で?
       (弥太郎)
 Function matt(adrs As Range)
    Dim x As Double, i As Integer, n As Integer
    Dim data As Double, s_data As Double, tbl As Range, y(2)
    Set tbl = adrs
    x = 500
    For i = 1 To tbl.Columns.Count
        data = Val(StrConv(tbl(1, i), vbNarrow))
        For n = i + 1 To tbl.Columns.Count
            s_data = Val(StrConv(tbl(1, n), vbNarrow))
            If data + s_data >= 150 Then
                If data + s_data - 150 < x Then
                    x = data + s_data - 150
                    y(0) = tbl(1, i).Address(0, 0)
                    y(1) = tbl(1, n).Address(0, 0)
                End If
            End If
        Next n
    Next i
    matt = x + 150 & "," & y(0) & "と" & y(1)
 End Function

    						


 2回給油分の組み合わせですか???
 3回分4回分等の組み合わせも有るのでしょうか???
 (JJ)

 	A	B	3回分4回分等の組み合わせも有るのでしょうか?	
 1	1	70			
 2	2	75			
 3	3	83			
 4	4	90			
 5	5	76			
 6	6	88			
 7	7	84			
 8	8	92			
 9	9	68			
 10	10	70			
 11	11	77			
 12	12	56			
 13	13	68			
 14	14	91			
 15	15	87			
 16					
 17	15回給油したとして				
 18	=COMBIN(15,2)=105の内一番近い数字を選ぶ(2回のみの組み合わせ) 

 19	=COMBIN(15,3)=455の内一番近い数字を選ぶ(3回のみの組み合わせ)				
 20	=COMBIN(15,4)=1365の内一番近い数字を選ぶ(4回のみの組み合わせ)     
         の内一番近い数字を選ぶになりますが				

 jj

 質問内容からすると
 n枚のレシートからm(1≦m≦n)枚取り出してその合計が150以上で
 最小値になる組み合わせを求めるということでしょうか。
 実際は、求めた組み合わせのデータを除いた中から同じように
 抽出を繰り返すのでしょう。
 (やっちん)

 な〜るほろ〜。
 いかにもありそうでんなぁ。
 ほならこないな事でっしゃろか?
 =mattaku(a1:j1,3) っちゅう塩梅に入力。抽出されたセルのデータを消去していく。
 組合せ4までですけど、それ以上あるばやいはコードの規則性に従って書き加えてく
 らはい。
 =mattaku(a1:j1)と引数を省略したら2回の組合せで抽出します。
       (弥太郎)
 Function mattaku(adrs As Range, Optional mai = 2)
    Dim x As Double, i As Integer, n As Integer, t As Integer, j As Integer
    Dim data1 As Double, data2 As Double, data3 As Double, data4 As Double, tbl As Range, y(3)
    Set tbl = adrs
    x = 1000
    With tbl
    Select Case mai
        Case 4
            For i = 1 To .Columns.Count - 3
                If tbl(1, i) <> "" Then
                    data1 = Val(StrConv(tbl(1, i), vbNarrow))
                        For n = i + 1 To .Columns.Count - 2
                            If tbl(1, n) <> "" Then
                                data2 = data1 + Val(StrConv(tbl(1, n), vbNarrow))
                                For j = n + 1 To tbl.Columns.Count - 1
                                    If tbl(1, j) <> "" Then
                                        data3 = data2 + Val(StrConv(tbl(1, j), vbNarrow))
                                        For t = j + 1 To tbl.Columns.Count
                                            If tbl(1, t) <> "" Then
                                                data4 = data3 + Val(StrConv(tbl(1, t), vbNarrow))

                                                If data4 >= 150 Then
                                                    If data4 - 150 < x Then
                                                        x = data4 - 150
                                                        y(0) = tbl(1, i).Address(0, 0)
                                                        y(1) = tbl(1, n).Address(0, 0)
                                                        y(2) = tbl(1, j).Address(0, 0)
                                                        y(3) = tbl(1, t).Address(0, 0)
                                                    End If
                                                End If
                                            End If
                                        Next t
                                    End If
                                Next j
                            End If
                        Next n
                End If
            Next i
            mattaku = x + 150 & "は" & Join(y, ",")
            Exit Function
        Case 3
            For i = 1 To .Columns.Count - 2
                If tbl(1, i) <> "" Then
                    data1 = Val(StrConv(tbl(1, i), vbNarrow))
                    For n = i + 1 To .Columns.Count - 1
                        If tbl(1, n) <> "" Then
                            data2 = data1 + Val(StrConv(tbl(1, n), vbNarrow))
                            For j = n + 1 To .Columns.Count
                                If tbl(1, j) <> "" Then
                                    data3 = data2 + Val(StrConv(tbl(1, j), vbNarrow))
                                    If data3 >= 150 Then
                                        If data3 - 150 < x Then
                                            x = data3 - 150
                                            y(0) = tbl(1, i).Address(0, 0)
                                            y(1) = tbl(1, n).Address(0, 0)
                                            y(2) = tbl(1, j).Address(0, 0)
                                        End If
                                    End If
                                End If
                            Next j
                        End If
                    Next n
                End If
            Next i
            mattaku = x + 150 & "," & y(0) & "と" & y(1) & "と" & y(2)
            Exit Function
        Case 2
            For i = 1 To .Columns.Count - 1
                If tbl(1, i) <> "" Then
                    data1 = Val(StrConv(tbl(1, i), vbNarrow))
                    For n = i + 1 To .Columns.Count
                        If tbl(1, n) <> "" Then
                            data2 = data1 + Val(StrConv(tbl(1, n), vbNarrow))
                            If data2 >= 150 Then
                                If data2 - 150 < x Then
                                    x = data2 - 150
                                    y(0) = tbl(1, i).Address(0, 0)
                                    y(1) = tbl(1, n).Address(0, 0)
                                End If
                            End If
                        End If
                    Next n
                End If
            Next i
    End Select
    If y(0) = "" Then Exit Function
    mattaku = x + 150 & "," & y(0) & "と" & y(1)
    End With
 End Function


 A1:A15 の範囲に(上から順に間を明かさず}リットル数を書き込んで、
 下記のマクロを実行してみて下さい。 
(純丸)(o^-')b  もっと配列の扱いがすっきり出来るんだろうなぁw

 Sub test2()
  Dim tbl1, tbl2
  Dim i As Long
  Dim ii As Integer
  Dim datacnt As Long
  Dim myans As Single
  Dim myans2 As Single
  Dim myans3 As Long
  datacnt = Application.WorksheetFunction.Count(Range("A1:A15"))
  Range("A1:A15").Font.ColorIndex = 0
  ReDim tbl1(1 To datacnt)
  ReDim tbl2(1 To datacnt)
  myans = 150
  For i = 1 To datacnt
    tbl1(i) = Cells(i, 1).Value
  Next i
  For i = 1 To 2 ^ datacnt
     For ii = 1 To datacnt
        tbl2(ii) = Int(i / (2 ^ (ii - 1))) Mod 2
     myans2 = myans2 + tbl1(ii) * tbl2(ii)
     Next ii
     myans2 = myans2 - 150
        If myans2 < 0 Then GoTo mynext
     If myans > myans2 Then
        myans = myans2
        myans3 = i
     End If
  mynext:
  myans2 = 0
  Next i
  For ii = 1 To datacnt
    If Int(myans3 / (2 ^ (ii - 1))) Mod 2 = 1 Then
       Cells(ii, 1).Font.ColorIndex = 3
    End If
  Next ii
  Range("A17").Value = Application.WorksheetFunction.RoundDown(myans, 1) + 150
 End Sub

 本当に正しいのか怪しいのですが(^^;
 無駄な動きをしている部分もありますが、とりあえず。
 A列に連番、B列に数値だけのデータを入力。C列は必ずクリアしておいてください。
 A列とB列をB列昇順に並び替えます。
 ここでTestを実行してください。
 D列に合計、E列に組み合わせの番号が出ます。

 Dim Min_Pt As String
 Dim Min_Sm As Double
 Dim MyArray As Variant
 Dim MaxRow As Long
 Const LMT150 = 150#

 Sub Test()
    Dim Cnt As Long
    Dim MyArray2 As Variant
    Dim j As Long
    Cnt = 0
    MyArray = Range(Range("A1"), Range("B" & Rows.Count).End(xlUp).Offset(, 1))
    MaxRow = UBound(MyArray, 1)

    Do
        Cnt = Cnt + 1
        Min_Sm = 9999999999999#
        Min_Pt = ""
        Call Kumiawase(0, 0, "", False)
        If Min_Pt <> "" Then
            Cells(Cnt, 4).Value = Min_Sm
            Cells(Cnt, 5).Value = Mid(Min_Pt, 2)
            MyArray2 = Split(Mid(Min_Pt, 2), ",")
            For j = 0 To UBound(MyArray2, 1)
                MyArray(Application.Match(Val(MyArray2(j)), Columns(1), 0), 3) = 1
            Next
        End If
    Loop Until Min_Pt = ""
 End Sub

 Sub Kumiawase(ByVal i As Long, ByVal Sm As Double, ByVal Pt As String, ByRef Flg As Boolean)
    Dim wk As Long
    If Sm >= LMT150 Then
        If Min_Sm > Sm Then
            Min_Pt = Pt
            Min_Sm = Sm
        End If
        Flg = True
        Exit Sub
    End If

    Do While i < MaxRow
        wk = ix(i + 1)
        If wk <= MaxRow Then
            Call Kumiawase(wk, Sm + MyArray(wk, 2), Pt & "," & MyArray(wk, 1), Flg)
            If Flg = True Then
                Flg = False
                Exit Sub
            End If
        End If
        i = ix(i + 1)
    Loop
 End Sub

 Function ix(ByVal i As Long) As Long
    ix = i
    Do While ix <= MaxRow
        If MyArray(ix, 3) <> 1 Then
            Exit Function
        End If
        ix = ix + 1
    Loop
 End Function
 (やっちん)


みなさん。ご回答有難うございました。まだまだ初心者の私にもなんとか出来ました。
とりあえず、やっちんさんのを使わせていただきます。
(MATT)

コメント返信:

[ 一覧(最新更新順) ]


YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki. Modified by kazu.