完全背包的深度优先搜索

1. 问题描述:

有n个重量和价值分别为wi,vi的物品,从这些物品中挑选出总重量不超过W的物品,求所有挑选方案中价值总和的最大值
1≤n≤100

1≤wi,vi≤100

1≤W≤10000

输入:

第一行是n

第二行到是物品的重量

第三行是物品对应的价值

而且物品的数量是无限的,可以无限拿取

2. 我们对于背包问题一般是使用动态规划进行推理来解决的,但是在一开始的时候对于这种求解最大价值的问题,我们完全是可以使用深度优先搜索来解决的,给出背包容量和价值那么我们尝试去拿取物品,因为是可以重复拿取的,那么我们应该先判断背包的容量是否能够装得下当前的物品,假如装得下那么我们就拿取当前这个物品,假如装不下那么我们就看能不能拿取下一个物品,试探所有的可能性,每一次装完物品之后那么我们需要计算背包中的价值看一下是否要更新当前的最大值

通过分析我们知道物品是可以重复拿取的,每一次都是尝试去拿取当前的物品,假如不能拿那么尝试拿取下一个物品,那么我们就拿取尝试拿取下一个物品,所以可以知道存在着n个平行的状态,(n为物品的数量)所以需要在一个for循环中去深度优先搜索,直到把所有的路径走完了,没走完一条路径就把装进背包的物品的价值给计算出来判断是否更新最大值那么最后得到的肯定是所有选择中价值最大的

这道题目有点像部分和的例子,给出一个目标数字使用当前可以选择的数字来构成这个目标数字,但是又有点不一样,部分和的题目数字是不可以重复拿取的,所以平行状态的数量也是不一样的,当时思路却是差不多的,都是尽可能来构成目标数字

我感觉最重要的是找出题目中存在的平行状态,画出搜索树,对于平行状态下退回来之后该怎么样进行处理,把上面的问题搞清楚那么深搜的代码就比较容易写了

2. 我们可以在for循环中使用if语句来判断是否能够拿取当前的物品,其中if语句可以起到两个作用:

①进行剪枝,发现合法的路径才搜索下去

②间接地充当了递归出口的作用

画出其中的搜索树来查看其中的dfs的调用过程:(物品质量:{7 4 3 2} 物品价值{9 5 3 1})

         

 

但是会发现其中有很多求解过的路径,但是这是在搜索的过程中无法避免的,因为它要搜索完全部的路径,所以要尝试每一种的可能性

3. 对于在退回到平行状态的时候那么我们应该对其进行处理,假如退回来的路径已经全部走完了那么我们应该与当前的max来判断一下来决定是否更新当前的max

所以对于走完每一条完整的路径它都会退回来继续搜索下一个平行的状态,那么这个时候就应该进行判断是否更新max

当退回到不是完整路径的节点的时候那么也会与当前的max比较,但是这个是不影响最终的结果的,因为不管是退回到完整路径的最后节点,还是不完整路径的节点它都是需要进行与当前max的比较的,因为它对于每个退回来的节点都是这样处理的,只不过完整的路径可能当前的max路径值更大

3. 具体的代码如下:

import java.util.Scanner;
public class Main{
    static int w[];
    static int v[];
    static int n;
    static int W;
    static int max = 0;
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        w = new int[n];
        v = new int[n];
        for(int i = 0; i < n; i++){
            w[i] = sc.nextInt();
        }
        for(int i = 0; i < n; i++){
            v[i] = sc.nextInt();
        }
        W = sc.nextInt();
        int ww = W;
        dfs(0,ww);
        System.out.println(max);
        sc.close();
    }
    private static void dfs(int vv, int ww){
        //v为当前物品的价值
        //可以发现存在着n个平行的状态
        for(int i = 0; i < n; i++){
            if(w[i] <= ww){
                dfs(vv + v[i], ww - w[i]);
                if(max < vv + v[i]){
                    max = vv + v[i];
                }
            }
        }
               return;
    }
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值