标签:不能 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