幸运的袋子

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

输入描述:

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

输出描述:

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

分析

如果直接遍历每种组合来寻找则需要搜索的空间过大,n个数一共有2^n个组合,程序复杂度过高。所以首先要根据条件进行剪枝:
首先考虑两个数a+b>a*b,可以写成1+x+1+y>(1+x)(1+y),1>xy,由于a,b为正整数,所以x,y必有一个为0,所以a,b必有一个为1。
当多个数时,如果sum

编程思路

使用DFS进行深度遍历搜索,然后配合剪枝。
剪枝:先对输入的数组进行升序排序,然后从两个数组合开始,{a0,a1},{a0,a1,a2}…{a0,a1,…,a(i-1)},{a0,a1,…,a(i-1),ai},每次增加一个数,直到{a0,a1,…,a(i-1),ai}不满足要求时停止,因为后边增加的数一定是大于等于ai的,无法满足幸运袋子要求,这里就完成剪枝。
最后还要注意处理重复的数字。

public class Main {
    public static void main(String[] args) {
        int[] a = {1,1,1,1,2,2,2,2};
        Arrays.sort(a);
        int[] b = new int[a.length];
        int b_length=0;
        b[0] = a[0];
        b_length++;
        DFS(a,b,1,b_length);
        System.out.println(sum);
    }

    static int sum = 0;
    public static void DFS(int[] a,int[] b,int index,int b_length) {
        // 处理重复数据的标志位
        boolean flag = true;
        for(int i=index;i<a.length;i++) {
            // 如果是第一次循环和前一个数相等,因为比前一个序列多了一位数,所以不是重复进行计算,
            // 如果不是第一次循环和前一个数相等时,则是重复,不进行计算
            if((a[i-1]==a[i]&&flag)||a[i-1]!=a[i]) {
                b[b_length] = a[i];
                b_length++;
                int p = compute(b,b_length);
                if(p==1) {
                    // 计算出来的符合条件的可以继续增加数据计算
                    sum++;
                    // 注意增加数据从i+1开始的
                    DFS(a,b,i+1,b_length);
                }else {
                    // 剪枝:不符合条件的因为增加的数据大于等于当前序列最大的数据,后边所有数据一定也不符合,所以剪枝
                    break;
                }
                b_length--;

                flag = false;
            }

        }
    }
    public static int compute(int[] b,int b_length) {
        long sum=0;
        long mutl=1;
        for(int i=0;i<b_length;i++) {
            sum+=b[i];
            mutl*=b[i];
        }
        if(sum>mutl)
            return 1;
        else
            return 0;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值