动态规划基本问题

01背包

问题描述:给定n个物体(它们的重量为:w1,w2,…,wn,价值为:v1,v2,…,vn) 和 一个承受重量为W的背包,问怎么选取这些物体,放在背包中(不超过背包的承重),让所取的子集达到最大价值。

  • 二维数组实现
  • 基本实现
    主要考虑两个基本问题
    (1)第n个物体不放进背包中;
    (2)第n个物体放进背包。
    递推式如下:
    在这里插入图片描述
  • 代码实现
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 = 1; i <= n; i++) {
			v[i] = scanner.nextInt();
		}
		for (int i = 1; i <= n; i++) {
			w[i] = scanner.nextInt();
		}
		int dp[][] = new int[n + 1][m+1];
		for (int i = 1; i <= n; i++) {
			for (int j = 1; j <= m; j++) {
				if(j >= w[i]) {
					dp[i][j] = Math.max(dp[i-1][j], dp[i-1][j - w[i]] + v[i]);
				}
			}
		}
		System.out.println(dp[n][m]);
	}
}
  • 一维数组实现
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 = 1; i <= n; i++) {
			v[i] = scanner.nextInt();
		}
		for (int i = 1; i <= n; i++) {
			w[i] = scanner.nextInt();
		}
//		int dp[][] = new int[n + 1][m+1];
		int dp[] = new int[m+1];
		for (int i = 1; i <= n; i++) {
		//注意这里是倒序
			for (int j = m; j >= w[i]; j--) {
				if(j >= w[i]) {
//					dp[i][j] = Math.max(dp[i-1][j], dp[i-1][j - w[i]] + v[i]);
					dp[j] = Math.max(dp[j], dp[j - w[i]] + v[i]);
				}
			}
		}
		System.out.println(dp[m]);
	}
}

完全背包

问题描述:完全背包是在01背包的基础上加了个条件——这n种物品都有无限的数量可以取,问怎样拿才可以实现价值最大化。

  • 基本实现
    递推式
    在这里插入图片描述
  • 二维数组实现
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 = 1; i <= n; i++) {
			v[i] = scanner.nextInt();
		}
		for (int i = 1; i <= n; i++) {
			w[i] = scanner.nextInt();
		}
		int dp[][] = new int[n + 1][m+1];
//		int dp[] = new int[m+1];
		for (int i = 1; i <= n; i++) {
			for (int j = 1; j <= m; j++) {
				if(j / w[i] >= 1) { //可以放置一件或一件以上的物品时
					int max = 0;
					for (int k = 1; k <= j / w[i]; k++) {//背包可以放置同一件物品多件
						if(dp[i-1][j - k * w[i]] + k * v[i] > max) {
							max = dp[i-1][j - k * w[i]] + k * v[i];
						}
					}
					dp[i][j] = Math.max(dp[i-1][j], max);
//					dp[j] = Math.max(dp[j], dp[j - w[i]] + v[i]);
				}
			}
		}
		System.out.println(dp[n][m]);
	}
}
  • 一维数组实现
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 = 1; i <= n; i++) {
			v[i] = scanner.nextInt();
		}
		for (int i = 1; i <= n; i++) {
			w[i] = scanner.nextInt();
		}
//		int dp[][] = new int[n + 1][m+1];
		int dp[] = new int[m+1];
		for (int i = 1; i <= n; i++) {
			for (int j = w[i]; j <= m; j++) {
//				if(j / w[i] >= 1) {
//					int max = 0;
//					for (int k = 1; k <= j / w[i]; k++) {//背包可以放置同一件物品多件
//						if(dp[j - k * w[i]] + k * v[i] > max) {
//							max = dp[j - k * w[i]] + k * v[i];
//						}
//					}
//					dp[i][j] = Math.max(dp[i-1][j], max);
					dp[j] = Math.max(dp[j], dp[j - w[i]] + v[i]);
//				}
			}
		}
		System.out.println(dp[m]);
	}
}

多种背包

问题描述:多重背包是在01背包的基础上,加了个条件:第 i 件物品有ni件。

  • 基本实现
    在这里插入图片描述
    代码实现如下所示,代码与完全背包的区别除了多了个表示物品个数的数组n[ ]之外,只在内循环的控制条件那里。
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];
		int amout[] = new int[n + 1];
		for (int i = 1; i <= n; i++) {
			v[i] = scanner.nextInt();
		}
		for (int i = 1; i <= n; i++) {
			w[i] = scanner.nextInt();
		}
		for (int i = 1; i <= n; i++) {
			amout[i] = scanner.nextInt();
		}
		int dp[][] = new int[n + 1][m+1];
//		int dp[] = new int[m+1];
		for (int i = 1; i <= n; i++) {
			for (int j = w[i]; j <= m; j++) {
				if(j / w[i] >= 1) {
					int max = 0;
					for (int k = 1; k <= j / w[i] && k <= amout[i]; k++) {//背包可以放置同一件物品多件
						if(dp[i-1][j - k * w[i]] + k * v[i] >  max) {
							max = dp[i-1][j - k * w[i]] + k * v[i];
						}
					}
					dp[i][j] = Math.max(dp[i-1][j], max);
//					dp[j] = Math.max(dp[j], dp[j - w[i]] + v[i]);
				}
			}
		}
		System.out.println(dp[n][m]);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值