“绿盟杯”决赛第二阶段(Java):背包问题

原题目:

挑战任务

小绿是“绿盟”的工程师,这次准备参加团队组织的团建,本次团建他要负责携带团队所有人的零食,小绿目前只有一个容量为bagCapacity的背包,现在总共有num袋零食,每袋零食的体积不一定相同;小绿现在想知道在零食的总体积不超过自己背包容量的情况下,总共可以有多少种放零食的方法(体积为0也是一种放法)。

分析

如果有num袋零食,那么所有可能的摆放情况数为组合数公式
刚开始的想法是直接用嵌套循环去搞定。但是嵌套的层数是不确定的:
如果摆放1袋零食,那么是一个单层循环;如果摆放2袋零食,那么想要判断所有可能的情况,需要一个双层嵌套循环;如果是3袋,那么需要三层…而我们需要讨论摆放0袋一直到摆放num袋的所有可能情况,这种算法实现起来非常困难(或者说根本不可能实现),所以只好另辟蹊径。

那么我们换一种思路,运用生活中的常识去解决问题:如果目前摆放n袋零食书包可以装得下,那么我们再从剩下的零食中拿一袋装进书包,可不可以装得下呢?如果可以,那我们再放进去一袋呢?如果不行,我们换一袋别的零食可不可以装得下呢?依此类推。
这就像我们日常生活中向包里面装东西的思路:挑一个放进包里,如果装不下就把这个拿出来,换一个放进去;如果装得下我们可能会继续向里面装其他东西。如此往复,直到装满为止。
这样的思路我们便可以用递归的方法去实现了。
源代码如下:

package app1;
import java.util.*;

public class Main {
        public static int ways = 0;//作为全局变量,统计所有可行的方案数

        public static void main(String[] args){//进行相关数据的输入、输出
                int num, bagCapacity;
                Scanner in = new Scanner(System.in);
                num = in.nextInt();//零食袋数
                bagCapacity = in.nextInt();//书包容量
                long[] snacks = new long[num];//每袋零食的体积
                for(int i = 0;i < num;i++){
                        snacks[i] = in.nextInt();//写入体积数据
                }
                getTheWay(num,bagCapacity,snacks,0,0);//调用递归函数统计方法数
                System.out.println("所有可能的情况数:"+ways);//输出结果
        }

        public static void getTheWay(int num, int bagCapacity,long[] snacks,long weight,int tag){
                if(weight <= bagCapacity){
                        ways++;//如果符合则方法数+1
                        for(int i=tag;i<num;i++){//看一看再装一袋零食可不可以
                                //变量tag是为了避免重复统计用的,具体可以参考穷举法
                                getTheWay(num,bagCapacity,snacks,weight+snacks[i],i+1);
                        }
                }
        }
}

测试结果:
①测试输入:20 130 1 5 2 1 9 3 23 12 3 4 7 8 10 11 12 13 14 15 16 12
输出结果:998906

②测试输入:21 1165911996 842104736 130059605 359419358 682646280 378385685 622124412 740110626 814007758 557557315 40153082 542984016 274340808 991565332 765434204 225621097 350652062 714078666 381520025 613885618 64141537 783016950
输出结果:703

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值