(最小元素个数)子集和问题--回溯法

子集和问题

代码
#迭代回溯
def MaxAdd(n,c,value,bestx):
    #n:数据个数
    #c:上界
    #value[]:数据列表
    #bestx[]:当前最优解
    i=1#从根节点出发
    x=[0 for i in range(n+1)]#x[1:i]是当前子集
    bestw=0#当前最优子集和
    cw=0#当前子集和
    r=0#剩余数的总和
    for j in range(1,n+1):
        r+=value[j]
    print("r",r)
    while True:
        while i<=n and cw+value[i]<=c:#左子树
            r-=value[i]
            cw+=value[i]
            x[i]=1
            i+=1
            print("第{}层".format(i-1))
            print("←添加",value[i-1])
            print("cw",cw)
            print("r",r)
        if i>n:
            print("第{}层".format(i))
            print("到达左叶子")
            for j in range(1,n+1):
                bestx[j]=x[j]
            bestw=cw
        else:#剪掉value[i]的左子树,搜索右子树
            r-=value[i]
            i+=1
            print("向右,不加",value[i-1])
            print("r",r)
            print("到第{}层".format(i))
        while cw+r<=bestw:#剪掉value[i-1]的右子树
            i-=1
            print("回退到",value[i])
            print("第{}层".format(i))
            print("cw",cw)
            print("r",r)
            while i>0 and (not x[i]):
                r+=value[i]
                i-=1
            print("一直回退到",value[i])
            if i==0:
                return bestw,bestx
            x[i]=0
            cw-=value[i]#不加入value[i]
            i+=1
    
n=5
c=10
value=[0,4,5,6,2,2]
bestx=[0 for i in range(n+1)]
r=0#剩余数的总和
for j in range(1,n+1):
    r+=value[j]

    
bestw,bestx=MaxAdd(n,c,value,bestx)
print("最大子集和为",bestw)
print("构成最大子集和的子集为:",end="")
for i in range(n+1):
    if bestx[i]:
        print(value[i],end=" ")
        

结果

在这里插入图片描述

最小元素个数子集和问题

代码
#迭代回溯
def MaxAdd(n,c,value,bestx):
    #n:数据个数
    #c:上界
    #value[]:数据列表
    #bestx[]:当前最优解
    i=1#从根节点出发
    number=100#初始化最优子集元素个数为一个足够大的数100
    x=[0 for i in range(n+1)]#x[1:i]是当前子集
    bestw=0#最优子集和
    cw=0#当前子集和
    r=0#剩余数的总和
    for j in range(1,n+1):
        r+=value[j]
    while True:
        #cw+value[i]<=c是约束函数
        #x.count(1)+1<=number是其中一个上界函数
        while i<=n and cw+value[i]<=c and x.count(1)+1<=number:#搜索左子树
            r-=value[i]
            cw+=value[i]
            x[i]=1
            i+=1
            print("第{}层".format(i-1))
            print("←添加",value[i-1])
            print("cw",cw)
            print("r",r)
            print()
        if i<=n and (cw+value[i]>c or x.count(1)+1>number):
            #约束条件剪掉value[i]的左子树或者上界函数剪掉value[i]的左子树
            #搜索右子树
            r-=value[i]
            i+=1
            print("向右,不加",value[i-1])
            print("r",r)
            print("cw",cw)
            print("到第{}层".format(i))
            print()   
        while cw+r<bestw or r==0:#上界函数剪掉value[i-1]的右子树
            #搜索到达叶子结点
            if cw>=bestw:
                print("第{}层".format(i))
                print("到达叶子")
                for j in range(1,n+1):
                    bestx[j]=x[j]
                #计算当前子集的元素个数
                number=bestx.count(1)
                print("元素个数number",number)
                bestw=cw
                print("最大子集和bestw",bestw)
                print()
            i-=1
            print("回退到",value[i])
            print("第{}层".format(i))
            print("cw",cw)
            print("r",r)
            while i>0 and (not x[i]):
                r+=value[i]
                i-=1
            print("一直回退到",value[i])
            if i==0:
                return bestw,bestx,number
            x[i]=0
            cw-=value[i]#不加入value[i]
            i+=1
            print("cw",cw)
            print("r",r)
            print()
c=10
value=[0,2,2,6,5,4]
#value=[0,4,6,5,2,2]
n=len(value)-1
bestx=[0 for i in range(n+1)]
bestw,bestx,number=MaxAdd(n,c,value,bestx)
print("最大子集和为",bestw)
print("构成最大子集和的子集元素个数为",number)
print("构成最大子集和的子集为:",end="")
for i in range(n+1):
    if bestx[i]:
        print(value[i],end=" ")
        

结果

在这里插入图片描述

发布了28 篇原创文章 · 获赞 4 · 访问量 2476

猜你喜欢

转载自blog.csdn.net/weixin_45050042/article/details/103102308