牛牛准备参加学校组织的春游, 出发前牛牛准备往背包里装入一些零食, 牛牛的背包容量为w。
牛牛家里一共有n袋零食, 第i袋零食体积为v[i]。
牛牛想知道在总体积不超过背包容量的情况下,他一共有多少种零食放法(总体积为0也算一种放法)。
输入包括两行
第一行为两个正整数n和w(1 <= n <= 30, 1 <= w <= 2 * 10^9),表示零食的数量和背包的容量。
第二行n个正整数v[i](0 <= v[i] <= 10^9),表示每袋零食的体积。
输出一个正整数, 表示牛牛一共有多少种零食放法。
3 10 1 2 4
8
三种零食总体积小于10,于是每种零食有放入和不放入两种情况,一共有2*2*2 = 8种情况。
import java.util.*; //就是全排列,只不过要注意 //虽然w在int范围内,但是呢,加起来的w_sum可能会超出范围,需要用long public class Main { public static int res = 1; public static void main(String[] args) { Scanner in = new Scanner(System.in); int n = in.nextInt(); int w = in.nextInt(); int[] nums = new int[n]; long sum = 0; for(int i = 0; i < n; i++) { nums[i] = in.nextInt(); sum += nums[i]; } if(sum <= w){ //特判情况 System.out.println((int)Math.pow(2,n)); return; } Arrays.sort(nums); dfs(nums,0, w, 0L); System.out.println(res); } public static void dfs(int[] nums, int start, int w, long w_sum) { for(int i = start; i < nums.length; i++) { if(w_sum + nums[i] > w) break; res++; dfs(nums,i + 1, w, w_sum + nums[i]); } } }
算法实现:
(0). 将n件物品分为两部分,保存前一部分所有可能取法的体积值
(1). 遍历剩余的后一部分的可能取法
(2). 对于每种状态计算背包容量与当前体积值的差值tmp,然后在集合left中二分查找第一个大于tmp的值的下标,此时下标就是在前一部分中有多少种状态与当前体积相加之和满足不超过背包容量的个数。
(3). 输出最终结果
import java.util.ArrayList; import java.util.Collections; import java.util.Scanner; /** * @version: 1.0 */ public class Main8 { /* static int num = 0; public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n = sc.nextInt();//零食袋数 int w = sc.nextInt();//背包载重 int v[] = new int[n];//每袋零食的重量 long total = 0; for (int i = 0;i<n;i++){ v[i] = sc.nextInt(); total+=v[i]; } if (total<=w) System.out.println((int)Math.pow(2,n)); else{ h(v,n,0,*//*(long)*//*0,w); System.out.println(num); } sc.close(); } private static void h(int v[],int n,int i,long sum,int w){ if(i == n && sum <= w){ num++; return; } if (sum > w) return; h(v, n, i+1, sum, w); h(v, n, i+1, sum+v[i], w); }*/ public static void main(String[] args) { int num = 0; Scanner sc = new Scanner(System.in); int n = sc.nextInt();//零食袋数 int w = sc.nextInt();//背包载重 int v[] = new int[n/2];//前1/2每袋零食的重量 ArrayList<Long> left = new ArrayList<>(); for (int i = 0;i<n/2;i++) v[i] = sc.nextInt(); h(v,n/2,0,0,left,w); Collections.sort(left); int vr[] = new int[n-n/2];//后1/2每袋零食的重量 for (int i = 0;i<(n-n/2);i++) vr[i] = sc.nextInt(); ArrayList<Long> right = new ArrayList<>(); h2(vr,n-n/2,0,0,right,w); for (long r: right) num+=getMin(left,r); System.out.println(num); sc.close(); } private static void h(int v[],int n,int i,long sum,ArrayList<Long> left,int w){//将重量方法left集合 if (sum>w) return;//总重量大于载重w,直接舍弃 if(i == n){ left.add(sum); return; } h(v, n, i+1, sum,left,w); h(v, n, i+1, sum+v[i],left,w); } private static void h2(int vr[],int n,int i,long sum,ArrayList<Long> right,int w){//将剩余重量放入right集合 if (sum>w) return;//总重量大于载重w,直接舍弃 if(i == n){ right.add(w-sum); return; } h2(vr, n, i+1, sum,right,w); h2(vr, n, i+1, sum+vr[i],right,w); } private static int getMin(ArrayList<Long> arr, long a) {//二分查找到第一个大于a的索引 int l = 0; int r = arr.size()-1; int mid; while (l<=r){ mid = (l+r)/2; if (arr.get(mid) > a) r = mid-1; else l = mid+1; } return l; } }
import java.util.*; public class Main{ static int res = 0;//种类计数 //n:零食的数量 //w:背包的容量 //v:每袋零食的体积 //i:考虑到第几个零食了 //cw:目前背包内已有的零食总重(必须定义为long,否则求和溢出,AC80%) public static void solution(int n,int w,int[] v,int i,long cw){ //回溯算法思想 if(i<n){ //未全部考虑完 solution(n,w,v,i+1,cw);//不放当前i的零食,直接考虑i+1 if(cw+v[i]<=w){ //放当前i的零食 res++; solution(n,w,v,i+1,cw+v[i]); } } } public static void main(String[] args){ Scanner scanner = new Scanner(System.in); int n = scanner.nextInt(); int w = scanner.nextInt(); int[] v = new int[n]; long sum = 0; for(int i=0;i<n;i++){ v[i]=scanner.nextInt(); sum=sum+v[i]; } if(sum<=w) System.out.println((int)Math.pow(2,n)); else{ solution(n,w,v,0,0); System.out.println(res+1); } } }
import java.util.*; public class Main { public static long result = 1; public static void main(String[] args) { Scanner input = new Scanner(System.in); int n = input.nextInt(); long w = input.nextInt(); long[] v = new long[n]; long sum = 0; for (int i = 0; i < n; i++) { v[i] = input.nextInt(); sum = sum + v[i]; } if (sum <= w) { System.out.println((int) Math.pow(2, n)); } else { state(v, 0, w, 0); System.out.println(result); } } public static void state(long[] v,int index, long w, long current){ if (index == v.length) return; if (current + v[index] <= w){ result++; state(v, index+1,w,current+v[index]); } state(v,index+1,w,current); } }