整数划分递归相关问题

                                           算法设计----整数划分递归相关问题

一.原问题

整数划分,是指把一个正整数n写成如下形式:

假设整数n,能被划分为i段n=a1+a2+...ai,其中ak为n中划分的最大整数(1<=ak<=n,1<=k<=i),则{a1,a2...ai}是n的ak的一个划分

当n=6时我们可以获得以下这几种划分

一共有11种

分析:讨论整数n和划分的最大整数m的关系,可以分为以下几种情况:

       ①当整数n==1,只有一种划分,即{1}

       ②当划分的最大整数m==1时,只有一种划分,即{1,1......1}

       ③当n<m时,整数n可以划分的最大的数为n,即f(n,n)种划分

       ④当n==m时,根据需不需要划分最大整数m,可以分为两种情况:

              a:需要划分最大整数为m,只有一种划分,即{m}

              b:不需要划分最大整数为m,即可能划分的最大整数为m-1,即有f(n,m-1)种划分

       ⑤当n>m时,根据需不需要划分最大整数m,可以分为两种情况:

              a:需要划分最大整数为m,所以继续在n-m中划分,划分的最大整数还可能为m,所以有f(n-m,m)种划分

              b:不需要划分最大整数为m,所以划分的最大整数可能为m-1,即有f(n,m-1)种划分

       综上所述的转移状态方程:

                                      1                  当 n==1或 m==1时

              f(n,m)=     f(n,n)           当n<m时

                                      1+f(n,m-1)   当n==m时

                                       f(n-m,m)+f(n,m-1)   当n>m时

python源代码:

​
#整数划分问题
#假设整数n,能被划分为i段n=a1+a2+...ai,其中ak为n中划分的最大整数(ak<=n,k<=i),其中{a1,a2...ai}是n的ak的一次划分
#现在求整数n能够划分成多少种
def huafen(n,m):  #n为整数,m为划分的最大整数,m<=n
    if(n==1 or m==1):
        return 1
    elif n==m:
        return 1+huafen(n,m-1) 
    elif(n<m):
        return huafen(n,n)
    else:
        return huafen(n,m-1)+huafen(n-m,m)

a=[]
t=0
def digui(sum,k,m,l):
    global a
    global t
    if(sum>l):
        return
    elif(sum==l):
        t+=1
        print("第",t,"种:")
        for x in range(len(a)-1):
            print(str(a[x])+"+",end="")
        print(a[-1])
        
    else:
        c=range(m)
        for y in reversed(c):
            y+=1
            sum+=y   
            a.append(y)    #加入到a列表中
            digui(sum,k+1,y,l)  #递归调用
            a.pop()   #出列表,恢复现场,回溯
            sum-=y  #恢复现场,回溯

def main():
    print("请输入一个整数:")
    v=int(input())
    p=huafen(v,v)
    print("该整数的划分一共有"+str(p)+"种")
    print("所有的划分如下:")
    digui(0,0,v,v)

main()

​

运行结果如下:

二.变形1

如果限制每一个划分的整数不能一样,即划分的每一个整数不同  ,则又有多少种划分呢?

其实我们只需在原问题进行修改即可:

①当m==1时,我们需要设置{1,1,1,....1}为0种

②当n>m时,我们需要修改的是当需要选取最大整数m时  ,我们将最大值m-1,即f(n-m,m-1) 种

其余的不需要修改   

pythoon源码:

#整数划分变形问题
def huafen(n,m):  #n为整数,m为划分的最大整数,m<=n
    if(n==1):
        return 1
    elif(m==1):   #当m==1时,设置1,1,1.....1}为0种
        return 0
    elif n==m:
        return 1+huafen(n,m-1)
    elif(n<m):
        return huafen(n,n)
    else:
        return huafen(n,m-1)+huafen(n-m,m-1)   #使下次划分的整数小于上次的划分的最大整数

a=[]
t=0
def digui(sum,k,m,l):
    global a
    global t
    if(sum>l):
        return
    elif(sum==l):
        t+=1
        print("第",t,"种:")
        for x in range(len(a)-1):
            print(str(a[x])+"+",end="")
        print(a[-1])
        
    else:
        c=range(m)
        for y in reversed(c):
            y+=1
            sum+=y
            a.append(y)
            digui(sum,k+1,y-1,l)   #这里需要将下一次的最大划分整数修改为上一次划分最大整数-1,不能与上一次相同
            a.pop()
            sum-=y

def main():
    print("请输入一个整数:")
    v=int(input())
    p=huafen(v,v)
    print("该整数的划分一共有"+str(p)+"种")
    print("所有的划分如下:")
    digui(0,0,v,v)
main()

运行结果如下:

三.变形2

如果限制每次划分的整数的个数 ,则又有多少种划分呢?(类似与盘子分苹果问题)

(其中n为整数,每次划分只能划分为m个数)

分析:①当m==1时,只有一种划分,即{n}

           ②当n<m时,由于划分的整数不可能为负数和小数,则划分不尽,所以为0

           ③当n==m时,也是只有一种划分。即{1,1,1,1...1}

           ④当n>m时,根据划分的整数中是否包含1,可以分为两种情况:

                 a:划分的整数中至少有一个1,则在n-1中继续划分为m-1份,即f(n-1,m-1)种划分

                 b:划分的整数中没有1,所以m个部分划分的整数必须都大于1,所以先给m个部分设为1,接着将剩余的n-m整数对m个部分分别加数,即要保证m个部分均大于1,即n-m>=m,则总共有f(n-m,m)种;如果n-m<m,则f(n-m,m)为0,所以条件②不能省略

          综上所述方程:

                              1    当m==1 或者 n==m 时

             f( n,m) =    0   当m>n时

                              f(n-1,m-1)+f(n-m,m)    当n>m时

python源代码:

#整数划分变形问题
def huafen(n,m):  #n为整数,m为每次划分的整数个数
    if(m==1 or n==m):
        return 1
    elif(m>n):   #当m>n时
        return 0
    else:
        return huafen(n-1,m-1)+huafen(n-m,m)   #选取至少有一个1和不选取1的种数
a=[]
t=0
def digui(sum,k,m,l,q):
    global a
    global t
    if(sum>l):
        return
    elif(k==q and sum==l):
        t+=1
        print("第",t,"种:")
        for x in range(len(a)-1):
            print(str(a[x])+"+",end="")
        print(a[-1])
        
    else:
        c=range(m)
        for y in reversed(c):
            y+=1
            sum+=y
            a.append(y)
            digui(sum,k+1,y,l,q)   
            a.pop()
            sum-=y

def main():
    v,g=map(int,input("请输入两个以空格隔开的数:").split())  #整数v,和每次划分的整数个数g
    p=huafen(v,g)  
    print("该整数的划分一共有"+str(p)+"种")
    print("所有的划分如下:")
    digui(0,0,v,v,g)
main()

 运行结果如下:

 三.变形3   

  如果n划分成若干个奇正整数之和 ,则这样有多少种划分?

       (f(n,m)代表有多少种划分,其中n为整数,m为不大于n的最大整数的划分)

分析:当m==1时,只有一种划分,即{1,1,...1}

           ②当m为奇数时:根据m和n的关系可以分成三种情况

                    a.当n<m时,则有f(n,n)种划分

                    b.当n==m时,根据是否选取最大整数m,可以分成两种情况

                                 *选取最大奇整数m,则只有一种划分,即{m}

                                  *不选取最大奇整数m,则共有f(n,m-2)种划分

                     c.当n>m时,根据是否选取最大整数m,可以分成两种情况

                                  *选取最大奇整数m,则共有f(n-m,m)种划分

                                  *不选取最大奇整数m,则共有f(n,m-2)种划分

           ③当m为偶数时:根据m和n的关系可以分成三种情况:

                    a.当n<m时,可以分成两类:(m为偶数,则m-1为最大奇数)

                                  *当n<m-1时,则共有f(n,n)种划分

                                  *当n==m-1时,则共有f(n,m-1)种划分

                    b.当n==m时,则共有f(n,m-1)种划分

                     c.当n>m时,根据是否选取最大奇整数m-1,可以分成两种情况

                                  *选取最大奇整数m-1,则共有f(n-m+1,m-1)种划分

                                  *不选取最大奇整数m-1,则共有f(n,m-3)种划分

python源代码:

def huafen(n,m):  #n为整数,huafen(n,m)代表:m为划分的最大整数共有多少种,m<=n
    if(m==1):  #若m==1
        return 1
    elif (m%2):  #若m为奇数
        if(n<m):  #n<m
            return huafen(n,n)
        elif(n==m):   #是否选取最大奇整数m
            return 1+huafen(n,m-2)
        else:    #是否选取最大奇整数m
            return huafen(n-m,m)+huafen(n,m-2)
    else:  #若m为偶数
        if(n<m):
            if(n<m-1):
                return huafen(n,n)
            else:
                return huafen(n,m-1)
        elif(n==m):
            return huafen(n,m-1)
        else:   #是否选取最大奇整数m-1
            return huafen(n-m+1,m-1)+huafen(n,m-3)
a=[]
t=0
def digui(sum,k,m,l):
    global a
    global t
    if(sum>l):
        return
    elif(sum==l):
        flg=1
        for x in a:   #在原问题答案的基础下,挑选出整数全部都是偶数的列表
            if(x%2==0):
                flg=-1
                break
        if(flg==1):
            t+=1
            print("第",t,"种:")
            for x in range(len(a)-1):
                print(str(a[x])+"+",end="")
            print(a[-1])
        
    else:
        c=range(m)
        for y in reversed(c):
            y+=1
            sum+=y
            a.append(y)
            digui(sum,k+1,y,l)
            a.pop()
            sum-=y

def main():
    print("请输入一个整数:")
    v=int(input())
    p=huafen(v,v)
    print("该整数的划分一共有"+str(p)+"种")
    print("所有的划分如下:")
    digui(0,0,v,v)
main()

运行结果如下:

         

         

猜你喜欢

转载自blog.csdn.net/hgnuxc_1993/article/details/109129049