标签:不能 java bsp 背包 调用 分支 main int 记忆化搜索
参考《挑战程序设计竞赛》p51
01背包问题
input:
4
5
2 3
1 2
3 4
2 2
output:
7(选择第0、1、 3号物品)
朴素解法:
c++版:
#include <iostream> using namespace std; int n,W; int *w,*v;//数组的指针 int max(int x, int y) { if (x>y) return x; return y; } int rec(int i, int j)//从数组下标为i的物品开始往后挑选总重小于j的物体,i从0开始 { int res; if (i==n) res=0;//没有物品了 else if (j<w[i]) res=rec(i+1,j);//重量j小于该组物品的重量,不能取 else res=max(rec(i+1,j),rec(i+1,j-w[i])+v[i]);//重量j大于该组物品的重量,能取;挑选和不挑选都尝试一下 return res; } int main() { cin >> n >> W;//n组物品,W:总重量 w = new int[n]; v = new int[n]; for (int i=0; i<n; i++) cin >> w[i] >> v[i]; cout << rec(0,W) << endl; }
Java版本
package 记忆化搜索; import java.util.Scanner; public class Main { static int[] w, v; public static void main(String[] args) { Scanner sc=new Scanner(System.in); int n=sc.nextInt(); int W=sc.nextInt(); w = new int[n]; v = new int[n]; for (int i=0; i<n; i++) { w[i]=sc.nextInt(); v[i]=sc.nextInt(); } System.out.println(rec(0,W)); } private static int rec(int i, int j) { if (i==w.length) { return 0; } if (j<w[i]) { return rec(i+1, j); } int a=rec(i+1, j); int b=rec(i+1, j-w[i])+v[i]; return Math.max(a, b); } }
这种方法的搜索深度是n,而且每一层的搜索都需要两次分支,最坏就需要O(2n)的时间。当n比较大时就没办法解了。所以要怎么办才好呢?为了优化之前的算法,我们看一下针对样例输人的情形下rec递归调用的情况。以下是rec(i,j)的模拟情况,i:第几组物品,j:重量
如图所示,rec以(3,2)为 参数调用了两次。如果参数相同,返回的结果也应该相同,于是第二次调用时已经知道了结果却白白浪费了计算时间。让我们在这里把第1次计算时的结果记录下来,省略掉第二次以后的重复计算试试看。
c++版本:
#include <iostream> #include <cstring> using namespace std; int n,W; int *w,*v; int **dp; int max(int x, int y) { if (x>y) return x; return y; } int rec(int i, int j)//从数组下标为i的物品开始往后挑选总重小于j的物体 { if (dp[i][j]>=0) return j[i[dp]];//和dp[i][j]的意义一样 int res; if (i==n) res=0; else if (j<w[i]) res=rec(i+1,j); else res=max(rec(i+1,j),rec(i+1,j-w[i])+v[i]); dp[i][j] = res; return res; } int main() { cin >> n >> W; w = new int[n]; v = new int[n]; dp = new int*[n+1]; for (int i=0; i<=n; i++) { dp[i] = new int[W+1]; memset(dp[i],-1,sizeof(int)*(W+1)); } for (int i=0; i<n; i++) cin >> w[i] >> v[i]; cout << rec(0,W) << endl; }
Java版本:
package 记忆化搜索; import java.util.Arrays; import java.util.Scanner; public class Main { static int[] w, v; static int[][] dp; public static void main(String[] args) { Scanner sc=new Scanner(System.in); int n=sc.nextInt(); int W=sc.nextInt(); w = new int[n]; v = new int[n]; for (int i=0; i<n; i++) { w[i]=sc.nextInt(); v[i]=sc.nextInt(); } dp=new int[n+1][W+1]; for (int i = 0; i < dp.length; i++) { Arrays.fill(dp[i], -1); } System.out.println(rec(0,W)); } private static int rec(int i, int j) { if (dp[i][j]>=0) { return dp[i][j]; } if (i==w.length) { return 0; } if (j<w[i]) { return rec(i+1, j); } int a=rec(i+1, j); int b=rec(i+1, j-w[i])+v[i]; int res=Math.max(a, b); dp[i][j]=res; return res; } }
c++版本解法:
#include <iostream> #include <cstring> using namespace std; int n,W; int *w,*v; int **dp; int max(int x, int y) { if (x>y) return x; return y; } int main() { cin >> n >> W; w = new int[n]; v = new int[n]; dp = new int*[n+1]; for (int i=0; i<=n; i++) { dp[i] = new int[W+1]; memset(dp[i],0,sizeof(int)*(W+1)); } for (int i=0; i<n; i++) cin >> w[i] >> v[i]; for (int i=0; i<n; i++) { for (int j=0; j<=W; j++) { if (j<w[i]) dp[i+1][j]=dp[i][j]; else dp[i+1][j] = max(dp[i][j],dp[i][j-w[i]]+v[i]); } } cout << dp[n][W] << endl; }
java版本:
参考代码:https://www.acwing.com/problem/content/submission/code_detail/3617/
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner scanner=new Scanner(System.in); int n=scanner.nextInt(); int m=scanner.nextInt(); int v[]=new int[n+1]; int w[]=new int[n+1]; for (int i = 0; i <n; i++) { v[i]=scanner.nextInt(); w[i]=scanner.nextInt(); } int f[][]=new int[n+1][m+1]; for (int i = 0; i <n ; i++) { for (int j = 0; j <=m ; j++) { if(j<v[i]) f[i+1][j]=f[i][j]; else f[i+1][j]=Math.max(f[i][j],f[i][j-v[i]]+w[i]); } } System.out.println(f[n][m]); } }
标签:不能 java bsp 背包 调用 分支 main int 记忆化搜索
原文地址:https://www.cnblogs.com/clarencezzh/p/10368986.html