背包问题(求和,神奇的口袋)java
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);
}
}
上一篇: 十大排序算法
下一篇: python 装饰器