zoukankan      html  css  js  c++  java
  • 算法题——一道数字组合的题目的求解

      题目:给定一个数字,和一个范围,产生所有在范围内的不重复的数字之和,和等于给定的数字。
        举例:给数字12,范围3-6。可以产生以下5个组合:
        1、3+3+3+3
        2、3+3+6
        3、3+4+5
        4、4+4+4
        5、6+6
      要求给出最快实现,并且是非递归。

      

      这是某人给我出的一道算法题。经过考虑,给出了解法。最快的谈不上(算法无止境、人外有人),没有用递归。

      还是以题目的例子说明,数字12,范围3-6。给出了5种组合。将这5种组合改写一下

        3+3+3+3=3*4+4*0+5*0+6*0  记作:(4,0,0,0)
        3+3+6=3*2+4*0+5*0+6*1    记作:(2,0,0,1)
        3+4+5=3*1+4*1+5*1+6*0    记作:(1,1,1,0)
        4+4+4=3*0+4*3+5*0+6*0    记作:(0,0,3,0)
        6+6=3*0+4*0+5*0+6*2     记作:(0,0,0,2)

      可以看出,本题就变成求各个数字的系数组合。求解这样的题目一般用递归(本题要求不能用递归)或者递推。

      在“遍历组合算法的模块化”中,介绍了解这类题的模块化代码。如下所示:

      Public Sub Traversal()
        Dim P() As Integer, K As Integer, IsGroup As Boolean

        InitData()                        注:初始化数组代码块

        K = P.GetUpperBound(0)

        Do
          If IsMatch()  Then                  注:判别是否满足条件的代码块
            OutputAnswer()                  注:输出解的代码块
          End If

          IsGroup = False

          Do
            Delta(K)                     注:P(K)自增加值的代码块
            Do
              If Overflow(K) Then             注:判断P(K)是否越界的代码块
                K = K - 1
                Exit Do
              Else
                If K < P.GetUpperBound(0) Then
                  K = K + 1
                  SetP(K)                注:依据条件设置P(K)值的代码块
                Else
                  IsGroup = True
                  Exit Do
                End If

              End If
            Loop
          Loop Until (K < 0 Or IsGroup = True)

        Loop Until K < 0

        SomeEndCode()                      注:求解结束的代码块

      End Sub

      上面的代码相当于伪代码。还要根据本题的实际情况,进行改写。

      首先,函数有输入参数:A——给定的数字;N——范围的下限;M——范围的上限

      函数有返回值,以字符串数组返回每一组解

      1、初始化数组的代码:

        Dim i As Integer, j As Integer
        Dim tS() As String = {}, T As Integer = -1
        Dim S As Integer


        For i = 0 To M - N - 1
          P(i) = 0
        Next
        P(M - N) = Int(A / M)
        S = P(M - N) * M

        最先想到的数组初始化的代码是所有的系数都是0,但是没有必要,最后的一个系数是和前面的系数相关的。

      2、判别是否满足条件的代码块:
        这个简单,S=A

      3、输出解的代码块:

        ReDim Preserve tS(T + 1)
        T += 1
        tS(T) = ""
        For i = 0 To M - N
          If P(i) > 0 Then
            For j = 1 To P(i)
              tS(T) &= (i + N).ToString & "+"
            Next
          End If
        Next
        tS(T) = tS(T).Substring(0, tS(T).Length - 1)
      4、P(K)自增加值的代码块:
        P(K) += 1                   

        S += K + N

      5、判断P(K)是否越界的代码块
        这个也很简单,S>A

      6、依据条件设置P(K)值的代码块
        这个分两种情况,若P(K)不是最后一个系数,设置为0;是最后一个系数,设置为最大可能的组合。

        If K < P.GetUpperBound(0) Then
          P(K) = 0
        Else
          P(K) = IIf(S > A, 0, Int((S - A) / M))
          S += P(K) * M
        End If

      7、求解结束的代码块

        把前面的解返回出去。

        Return tS

      至此,代码改写完毕。完整的代码如下:

      Public Function Traversal(ByVal A As Integer, ByVal N As Integer, ByVal M As Integer) As String()
        Dim K As Integer, IsGroup As Boolean
        Dim P(M - N) As Integer
           

        Dim i As Integer, j As Integer
        Dim tS() As String = {}, T As Integer = -1
        Dim S As Integer


        For i = 0 To M - N - 1
          P(i) = 0
        Next
        P(M - N) = Int(A / M)
        S = P(M - N) * M

        K = P.GetUpperBound(0)

        Do

          If S = A Then                         

            ReDim Preserve tS(T + 1)
            T += 1
            tS(T) = ""
            For i = 0 To M - N
              If P(i) > 0 Then
                For j = 1 To P(i)
                  tS(T) &= (i + N).ToString & "+"
                Next
              End If
            Next
            tS(T) = tS(T).Substring(0, tS(T).Length - 1)
          End If

              

          IsGroup = False

          Do
            P(K) += 1                   
            S += K + N
            Do
              If S > A Then           
                S -= (K + N) * P(K)
                K = K - 1

                Exit Do
              Else
                If K < P.GetUpperBound(0) Then
                  K = K + 1

                  If K < P.GetUpperBound(0) Then
                    P(K) = 0
                  Else
                    P(K) = IIf(S > A, 0, Int((S - A) / M))
                    S += P(K) * M
                  End If
                Else
                  IsGroup = True
                  Exit Do
                End If

              End If
            Loop
          Loop Until (K < 0 Or IsGroup = True)

        Loop Until K < 0


        Return tS

      End Function

  • 相关阅读:
    JDBC
    「题解」:串串香
    「题解」:树
    「题解」:最近公共祖先
    「题解」:集合论
    「题解」:位运算
    「题解」:序列
    「总结」浅谈主席树
    $My$ $template$(持续更新)
    「题解」:毛三琛
  • 原文地址:https://www.cnblogs.com/grenet/p/2000549.html
Copyright © 2011-2022 走看看