欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

背包问题(求和,神奇的口袋)java

程序员文章站 2022-06-01 20:23:21
...

1.求和

输入两个整数 n 和 m,从数列1,2,3.......n 中随意取几个数,使其和等于 m ,要求将其中所有的可能组合列出来

题目解析:基于递归实现 dfs(深度优先搜索) 即可. 这是一个比较典型的背包问题

思路:假设问题的解为F(n, m),可分解为两个子问题 F(n-1, m-n)和F(n-1, m)。对这两个问题递归求解,求解过程 中,如果找到了符合条件的数字组合,则打印出来 例如 1, 2, 3, 4, 5, 求有多少中组合和为 5 对于 1 这个元素 来说, 可能会放到结果中, 可能不放到结果中 如果放到结果中, 就相当于求 2...5 中取若干个数字和为 4. (即为 F(n-1, m-n)) 如果不放到结果中, 就相当于求 2...5 中取若干个数字和为 5. (即为F(n-1, m))


import java.util.ArrayList;
import java.util.Scanner;

public class Main { 
// res 用于保存最终结果
    static ArrayList<ArrayList<Integer>> res = new ArrayList<ArrayList<Integer>>();
    static ArrayList<Integer> list = new ArrayList<>();

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n, m;
        while (sc.hasNext()) {
            n = sc.nextInt();
            m = sc.nextInt();       
            // 核心逻辑在此. 注意理解 m, n 的含义.          
            // 题目要求是求 1...n 中取若干个数, 和为 m
            dfs(1, m, n);        
            // 打印结果集合
            for (ArrayList<Integer> l : res) {
                int i = 0;
                for (; i < l.size() - 1; i++) {
                    System.out.print(l.get(i) + " ");
                }
                System.out.println(l.get(i));
            }
        }
    }

    public static void dfs(int index, int count, int n) {
        if (count == 0) {
            res.add(new ArrayList<>(list));
        } else {
            for (int i = index; i <= count && i <= n; i++) {
                list.add(i);            
                // 此处进行了递归, 对问题进行拆解.              
                // 求 1...n 中取若干个数字和为 m, 能把问题拆解为             
                // 求 2...n 中取若干给数字, 和为 m - 1
                dfs(i + 1, count - i, n);
                list.remove(list.size() - 1);
            }
        }
    }
}

2.神奇的口袋

有一个神奇的口袋,总的容积是40,用这个口袋可以变出一些物品,这些物品的总体积必须是40。John现在有n个想要得到的物品,每个物品的体积分别是a1,a2……an。John可以从这些物品中选择一些,如果选出的物体的总体积是40,那么利用这个神奇的口袋,John就可以得到这些物品。现在的问题是,John有多少种不同的选择物品的方式。

这是一个排列组合的问题。

题目解析: 采用递归思想: ①物品n个,物品体积逐一放入weight[]中 ②递归函数count(int s,int n) : 其 中s为剩余物品重量,n为剩余可选的物品个数
则分以下两步递归求解:
a.从后往前装,装上weight[n]后,若剩余物品仍然有解 则count(s-weight[n],n-1);
b.若装了weight[n]后,无解,则删除该包,尝试第n-1个 count(s,n-1);

import java.util.*;

public class test {
    static int[] weight;
    static int N;
    static int count = 0;

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);

        while (input.hasNext()) {
            N = input.nextInt();
            weight = new int[N + 1];

            for (int i = 1; i <= N; i++) {
                weight[i] = input.nextInt();
            }
            count(40, N);
            System.out.println(count);
        }
    }

    public static void count(int s, int n) {     //如果正好装满
        if (s == 0) {
            ++count;
            return;
        }
        //是s<0或n<1则不能完成
        if (s < 0 || (s > 0 && n < 1)) return;
        count(s - weight[n], n - 1);
        count(s, n - 1);
    }
}

 

 

相关标签: 编程