关于0-1背包的动规实现以及空间复杂度的优化算法

众所周知,动态规划的典型案例-背包问题实在竞赛中经常出现的,运用模板dp[][]来记录每次动规出来的结果往往不满足JVM的空间复杂度要求。

算法优化思路:寻常条件下,用dp[][]二维数组记录在特定的重量下装入的最优情况。其递推公式为F[i][v] = max{ F[i-1][v], F[i-1][v-C[i]] + W[i]}; 不难看出,对于记录的情况无非F[i-1][v]以及F[i-1][v-C[i]] + W[i]两种情况,因此F[i][j]的值只与其之前的值有关。基于此种特性,我们将每次伴随物品数量的装载,运用倒序导入的方式对数组dp【】进行更新,最终得到最优值。

以下为0-1背包问题基于空间复杂度要求的条件下做出的算法优化

package com.nowcoder;

import java.util.Scanner;

public class CharmBracelet {
	private static int maxValue2(int N, int V, int[] W, int[] C) {
		// 使用一维数组来做 降低了空间复杂度
		// 这里F[v] 代表v空间的背包所能达到的最大价值
		int[] dp = new int[V+1];

		for (int i=1; i <= N; i++) {
			for (int j=V; j >=W[i]; j--) {
				dp[j] = Math.max(dp[j], dp[j-W[i]]+C[i]);
			}
		}
		return dp[V];
	}
 
	public static void main(String[] args) {
		Scanner sc=new Scanner(S
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
0-1背包问题是一个经典的组合优化问题,其中给定一组物品和一个背包,每个物品有一个重量和一个价值,目标是找到一种最佳的方式将物品放入背包中,使得背包中物品的总价值最大,同时不能超过背包的容量。 回溯算是一种穷举搜索的方,它通过递归地尝试所有可能的解决方案来解决问题。在0-1背包问题中,回溯算通过递归地尝试将每个物品放入背包或不放入背包来生成所有可能的解决方案,并找到最优解。 分支限界算是一种优化的搜索方,它通过剪枝操作来减少搜索空间。在0-1背包问题中,分支限界算通过计算每个节点的上界(即当前节点的最大可能价值),并根据上界进行剪枝操作,从而减少搜索的时间复杂度。 回溯算的时间复杂度取决于搜索树的大小,最坏情况下为指数级别。空间复杂度取决于递归调用的深度,最坏情况下为O(n),其中n是物品的数量。 分支限界算的时间复杂度也取决于搜索树的大小,最坏情况下为指数级别。空间复杂度取决于优先队列的大小,最坏情况下为O(n),其中n是物品的数量。 以下是0-1背包问题的回溯算和分支限界算实现示例: 回溯算实现: ```python def backtrack(items, capacity, current_weight, current_value, best_value, selected): if current_weight > capacity: return if current_value > best_value[0]: best_value[0] = current_value best_solution[0] = selected.copy() if not items: return item = items[0] items = items[1:] selected.append(item) backtrack(items, capacity, current_weight + item.weight, current_value + item.value, best_value, selected) selected.pop() backtrack(items, capacity, current_weight, current_value, best_value, selected) # 初始化数据 items = [(1, 2), (2, 3), (3, 4), (4, 5)] capacity = 7 best_value = [0] best_solution = [[]] # 调用回溯算 backtrack(items, capacity, 0, 0, best_value, []) # 输出结果 print("Best value:", best_value[0]) print("Best solution:", best_solution[0]) ``` 分支限界算实现: ```python import heapq class Node: def __init__(self, level, weight, value, bound, selected): self.level = level self.weight = weight self.value = value self.bound = bound self.selected = selected def __lt__(self, other): return self.bound > other.bound def branch_and_bound(items, capacity): items.sort(key=lambda x: x[1] / x[0], reverse=True) queue = [] best_value = 0 best_solution = [] root = Node(0, 0, 0, 0, []) root.bound = compute_bound(root, items, capacity) heapq.heappush(queue, root) while queue: node = heapq.heappop(queue) if node.bound < best_value: continue if node.level == len(items): best_value = node.value best_solution = node.selected continue item = items[node.level] if node.weight + item[0] <= capacity: selected = node.selected.copy() selected.append(item) left_child = Node(node.level + 1, node.weight + item[0], node.value + item[1], 0, selected) left_child.bound = compute_bound(left_child, items, capacity) if left_child.value > best_value: best_value = left_child.value best_solution = left_child.selected if left_child.bound >= best_value: heapq.heappush(queue, left_child) right_child = Node(node.level + 1, node.weight, node.value, 0, node.selected) right_child.bound = compute_bound(right_child, items, capacity) if right_child.bound >= best_value: heapq.heappush(queue, right_child) return best_value, best_solution def compute_bound(node, items, capacity): bound = node.value weight = node.weight level = node.level while level < len(items) and weight + items[level][0] <= capacity: bound += items[level][1] weight += items[level][0] level += 1 if level < len(items): bound += (capacity - weight) * items[level][1] / items[level][0] return bound # 初始化数据 items = [(1, 2), (2, 3), (3, 4), (4, 5)] capacity = 7 # 调用分支限界算 best_value, best_solution = branch_and_bound(items, capacity) # 输出结果 print("Best value:", best_value) print("Best solution:", best_solution) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值