深度优先搜索+剪枝实战,你都弄懂了吗

我必须记这样一个坑爹的校招题

题目描述

一个袋子里面有n个球,每个球上面都有一个号码(拥有相同号码的球是无区别的)。如果一个袋子是幸运的当且仅当所有球的号码的和大于所有球的号码的积。
例如:如果袋子里面的球的号码是{1, 1, 2, 3},这个袋子就是幸运的,因为1 + 1 + 2 + 3 > 1 * 1 * 2 * 3
你可以适当从袋子里移除一些球(可以移除0个,但是别移除完),要使移除后的袋子是幸运的。现在让你编程计算一下你可以获得的多少种不同的幸运的袋子。

输入描述:

第一行输入一个正整数n(n ≤ 1000)
第二行为n个数正整数xi(xi ≤ 1000)

输出描述:

输出可以产生的幸运的袋子数

-----------------------------------------------------------------------------------------------------------

以上是题目,这样一个题目,我一开始拿到的时候是比较清晰的,结果被大佬的代码越搞越晕。什么dfs咯,什么剪枝咯,什么去重咯;其实这些我都有想到,但是无奈没有一个好的方法实现它;现在一缕,我感觉我的思路还是蛮清晰的:

1 排序;为什么要排序,因为这个题穷举的方法很显然是2^n次方个解,这么多的解,你就用暴力?时间不爆,天理不容。好的,那么排序有什么用呢,当然是去冗余了呀,你想想,凡是这种超大规模解的情况,肯定是要想办法去冗余的。如果排序之后,再添加元素一旦不满足条件了,好的,后面的都不用看了。

2 深度优先搜索,现在我们假设是这样的一种情况:排序后的输入1,1,1,2,2,3,4。我们考虑的方法是,首先:把第一个数扔进来,此时s=1,m=1,c=0,(s是和,m是积,c是count,即要求的种类),然后拿第二个进来,是1,满足,因为1+1>1*1,既然满足的话,count当然多了一种了,c+=1;我就一直往后面依次扩张,中间省略一些,结果就是:1,1,1,2,2,继续增加3,嘣!爆了,完了,怎么办?那么后面的4就不用看了,这一轮肯定爆,现在就要回到爆的位置,这个步骤叫:回溯。即回到1,1,1,2,2,然后呢?现在相当于是1,1,1,2,2已经考虑完了,要把第二个2,替换成3,即考虑1,1,1,2,3,好的,这个也满足,count继续+1,由于深度优先,一直要把你搞爆才行,所以下一个:1,1,1,2,3,4,爆。回溯,考虑,1,1,1,2,4,满足,count+1,但是到头了。那就收工了?肯定不是,继续回溯,到1,1,1,2(这个2是第二个2),这个熟悉不,好像刚才我们已经算了1,1,1,2了,现在岂不是又要算一遍,而且还都是一样的,我们的目标是:没有冗余!那这样子就当然要去重了。

好的,用上述方法,一直找到最后的count,就是答案!

现在有个问题,我之前是想到了这个方法,但是如果用两个变量i,j去检测两个数的,用i,j,k去检测3个数的,那到最后岂不是要用n个变量去遍历n个数,笑哭。那其实现在有一个方法,就是递归的方法,总共只用一个变量index,表示我要把谁给添加进原来的数组中。

3 上代码:

n=input()
x=sorted(map(int,input().strip().split(' ')))
def get_count(array,sumv=0, multiv=1):
    count=0
    for i in range(len(array)):
        if i>0 and array[i]==array[i-1]:  # 去重在这里
            continue
        sumv+=array[i]
        multiv*=array[i]
        if sumv > multiv:#array[i]可以选择移除或不移除,故count+1
            count+=1+get_count(array[i+1:], sumv, multiv)
        elif array[i]==1:#array[i]不移除,1可以提高sumv值,保持multiv不变(这里我想了一下,应该是只有第一次遇到1的时候会出现这样尴尬的情况,s不大于m,而输入的却是1)
            count+=get_count(array[i+1:], sumv, multiv)
        else:
            break
        #回溯
        sumv-=array[i]
        multiv/=array[i]
    return count
print(get_count(x))

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值