Sticks(DFS+剪枝)之Python解

        作为一名自学为主的中学生,我对很多时候那种因为难以完成一项任务而寝食难安的感受深有体会,同样,新高考形势下,编程言语的不同也成为了令广大中学生颇为头疼的一件事,我也同样对此十分苦恼,常常找不着合适的参考代码。

        为此,我现在将发布我的第一篇博客——关于Sticks问题的python代码——希望能够对广大读者有所帮助。

        话不多说,下面进入正题。

问题描述

    乔治拿来一组等长的木棒,将它们随机地砍断,使得每一节木棍的长度都不超过50个长度单位。然后他又想把这些木棍恢复到为裁截前的状态,但忘记了初始时有多少木棒以及木棒的初始长度。请你设计一个程序,帮助乔治计算木棒的可能最小长度。每一节木棍的长度都用大于零的整数表示。

输入格式
  输入包含多组数据,每组数据包括两行。第一行是一个不超过64的整数,表示砍断之后共有多少节木棍。第二行是截断以后,所得到的各节木棍的长度。在最后一组数据之后,是一个零。

输出格式
  为每组数据,分别输出原始木棒的可能最小长度,每组数据占一行。

样例输入
9
5 2 1 5 2 1 5 2 1
4
1 2 3 4
0

样例输出
5
6

算法思路

    通过问题描述可以初步得知,木棒的最小可能长度至少要大于木棒长度序列中的最大值且一定能被木棒长度序列之和整除。因此我们就可以我们就可以在这两个上下界之间,通过深度搜索的方式不断的试探每一个可能的最小长度,若试探成功则该长度即为木棒的最小可能长度,若失败则进行下一个可能的长度进行试探,直至成功。

        下面是我用python编写的一段代码,并进行了计时,感觉当数据量不大时并不比C++来得慢多少。

        我对其进行了详尽的注释,以保证大家绝对能看懂,再看不懂私聊。(QQ:3524575922)

from time import time


def dfs(i,l):                       #切割木条(DFS:深度优先搜索)
    
    if lens[l]==0:                  #当前木条刚好切完
        
        if  not any(lens):          #木条全部为0,即全部切下时成功返回
            return True
        i=1
        while used[i]:
            i+=1
        used[i]+=1;lens[l+1]-=sticks[i]     #剪枝:该木棒当前最长,一定要用
        
        if dfs(i+1,l+1):
            return True
        
        used[i]=0;lens[l+1]+=sticks[i]     #若失败返回,则恢复递归前状态
        
    else:
        for j in range(i,num):
            if j>0 and sticks[j]==sticks[j-1] and (not used[j-1]):
                continue
                                        #剪枝:相同长度,若上一根未选用,
                                        #这根同样无需考虑,直接跳过即可
            if (not used[j]) and lens[l]>=sticks[j]:
                                    #剪枝(最基本):木棒未使用且小于长木条剩余长度
                lens[l]-=sticks[j];used[j]=1
                
                if dfs(j,l):        #递归,进一步搜索
                    return True
                
                lens[l]+=sticks[j];used[j]=0    #若失败返回,则恢复递归前状态
                if sticks[j]==lens[l]:
                    break
    
    return False
    


def ts(l,s):                                        #条数是否大于一条
    
    yz=[]
    for i in range(l[0],s//2+1):
        if s%i==0:
            yz.append(i)
    return yz                       #找出并返回符合条件的因子,若无则返回空列表
   
 
if __name__=='__main__':
    
    print('请按提示输入相关信息,输入木棒数量为0时程序结束')
    
    num=int(input('\n请输入木棒数量:\n'))
    while num:
        sticks=list(map(int,input('请输入每根木棒长度:\n').split()))
                                            #读入木棒长度,并以列表形式储存        
        time_begin=time()                   #开始计时
        sticks.sort(reverse=True)           #剪枝:按降序排序
        
        _sum=sum(sticks)                    #木棒总长
        
        yz=ts(sticks,_sum)                  #按升序存储长木条可能的长度
        for len in yz:
            used=[0]*num                    #初始化used全部为0(未使用)
                                            #放在for 循环下,每次重新尝试时重置
            lens=[len]*int(_sum/len)
            
            if dfs(0,0):                    #调用递归函数
                time_end=time()
                print(len)
                break
        else:
            time_end=time()
            print(_sum)
                                            #停止计时,并输出结果        
        times=(time_end-time_begin)*1000
        print('耗时:',times,'ms')
        num=int(input('\n请输入木棒数量:\n'))
    input('\n请按任意键退出')

         让我们来看看运行效果如何吧。

  Oh,no.快到time模块计不出时了都。

而且本篇程序多以列表形式存储,便于调试和Debug。

         谨以此篇献给广大有需求的读者们。感谢各位读者的支持,希望能对你们有所帮助,这将是我最大的荣耀与动力。若有错误,欢迎大佬指出,便于更正,有幸承蒙醍醐灌顶之教,鄙人不胜感激之至。

        若喜欢,请点赞or收藏,谢谢!

更多博文欢迎访问我的CSDN主页https://blog.csdn.net/Forever_Sirius?type=blog

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值