这两天有个问题把我搞得乱糟糟的,到现在还是思维杂乱中。忽然想到应该来这里问问高手们啊。问题看起来容易,可是细想也会挺复杂的,请大家考虑全面点哦:前提:
A,B,C,D四个对象。
A,B可以生产I,II,III三个产品,有公式f(a,b,c)可以计算其总耗。
C,D可以生产I,II两个产品,有公式f(a,b)可以计算其总耗。
每个对象有两种状态:正常,故障。
正常状态时若对象分摊到I或II或III的生产,则都有一个最小生产量IminA,IminB,IminC,IminD,IIminA,IIminB,IIminC,IIminD,IIIminA,IIIminB和最大生产量ImaxA,ImaxB,ImaxC,ImaxD,IImaxA,IImaxB,IImaxC,IImaxD,IIImaxA,IIImaxB,即其产值或是0或是介于最小生产量和最大生产量(包括端点)之间。要求:
输入要生产的总的I、II、III,把所有可能的分配方案列出来,并计算出总耗。虽然是想求最优化的方案(即总耗最低的),但因为有时最优化的方案未必是用户根据实际诸多因素最想采取的方案,所以还是把所有组合按总耗排序列出来让用户选择的好,程序只起参考作用。
排序部分很容易实现,不需要大家分神考虑了,现在就需要一个高效而准确的所有可能方案的产生。问题:
一般的想法是作个7层的简单循环嵌套,但是耗时巨长,所以要充分考虑一些潜在筛选条件才能争取较快地得到所有方案。如当Ia在未超出A所允许的I的最大生产量IMaxA,但已超过所想生产的总的I时就不必继续其他循环了。
为什么是7层而不是10层,因为略去了一层I一层II和一层III循环,大家知道循环嵌套一层就是加大一个几何级,300^10 是个什么概念? 所以能减则减,就用I-Ia-Ib-Ic得到Id省去Id的循环,同理省去IId和IIIb的循环。增加复杂的因素1:嵌套顺序。
考虑:
当I=13,而Id最大值ImaxD=6,最小值IminD=1时
for Ia=0 to 5
   for Ib=0 to 3
      for Ic=0 to 2
          Id=I-Ia-Ib-Ic    ’实际到Id时的计算得值范围为13到3
          if Id>ImaxD then exit for  ’大于6的略去
          ....       '但是因为Id排在嵌套较里层,因此最终到3为止,而没能算到其真正的最小值,即丢失一部分区间。如果它排在外层自然不会这样,但另一个排在里层的也会如此。增加复杂的因素2:是否故障状态
如果故障,则只取生产值0,而不必再从最小值到最大值(或反向)循环,还是因为循环嵌套的层数问题,即使是空循环体的七层循环也要20多分钟。但是也不能简单地跳出循环,对于最里层的循环体还可以跳出,但外层的不可以,因为因为它的故障一跳出就使其它正常的对象也无法执行到了。那么如何才能既很好地利用工作状态来减少不必要的循环数量,又使每个故障的对象不会影响到其它的对象参与组合呢??大家先想,如果觉得还不明确,明天我把代码贴上一点,肯定是不理想的代码,大家修正补充一下,让它达到要求。

解决方案 »

  1.   

    N8test = N9test = N10test = 0
      GdTest8 = GdTest9 = GdTest10 = 0
      GgTest8 = GgTest9 = 0  If Check8 Then
        If Check9 Then
          If Check10 Then
            If Check11 Then
              MsgBox "所有车间停产,无法承担生产任务。", vbExclamation, "错误信息"
              Exit Sub
            Else
              N11test = TxtTotalN - N8test - N9test - N10test
              If N11test > 0 Then
                If N11test > Nmax11 Or N11test < Nmin11 Then Exit for
              End If
              Calc消耗
            End If
          Else
            To10jz
          End If
        Else
          To9jz
        End If
      Else
        For N8test = 0 To Nmax8 Step txtbc(0)
          If N8test > TxtTotalN Then Exit For
          If N8test = TxtTotalN Then
            Calc消耗
            Exit For
          End If
          If Check9 Then
            If Check10 Then
              CalcGin
            Else
              To10jz
            End If
          Else
            To9jz
          End If
          IF N8TEST=0 THEN N8TEST=Nmin8
        Next
      End If
    END SUBSUB Calc消耗
      Gin8 = CalcGin8(N8test, GdTest8, GgTest8)
      Gin9 = CalcGin9(N9test, GdTest9, GgTest9)
      Gin10 = CalcGin10(N10test, GdTest10)
      Gin11 = CalcGin11(N11test, GdTest11)
      Gin = Gin8 + Gin9 + Gin10 + Gin11
    END SUB