动态规划 | 完全背包问题笔记 | 代码随想录

跟随carl代码随想录刷题
语言:python


完全背包

⭐️每种物品都有无数件。

⭐️遍历顺序:

  • 01背包的内循环是从大到小遍历的
    • 再次强调:
      • 01背包中二维dp数组的两个for遍历的先后顺序可以颠倒。
      • 一维dp数组的两个for循环先后顺序必须是先遍历物品再遍历背包容量
  • 而完全背包的内循环是从小到大遍历的
    • 纯完全背包的一维dp数组两个for循环的嵌套顺序不重要。
      • 因为dp[j] 是根据 下标j之前所对应的dp[j]计算出来的。 只要保证下标j之前的dp[j]都是经过计算的就可以了。

先遍历物品,再遍历背包

def test_complete_pack1():
	weight = [1, 3, 4]
	value = [15, 20, 30]
	bag_weight = 4

	# 初始化
	dp = [0] * (bag_weight + 1)
	
	# 先遍历物品
	for i in range(len(weight)):
		# 再遍历背包
		for j in range(weight[i], bag_weight + 1):
			dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
	print(dp[bag_weight])

先遍历背包,再遍历物品

def test_complete_pack2():
	weight = [1, 3, 4]
	value = [15, 20, 30]
	bag_weight = 4

	# 初始化
	dp = [0] * (bag_weight + 1)
	
	# 先遍历背包
	for j in range(bag_weight + 1):
		# 再遍历物品
		for i in range(len(weight)):
			if j >= weight[i]:
				dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
	print(dp[bag_weight])
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用分支限界法解决01背包问题的C语言代码,已经添加了注释: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX_N 100 // 物品数量最大值 #define MAX_W 1000 // 背包容量最大值 /* 物品结构体 */ typedef struct { int w; // 物品重量 int v; // 物品价值 } Item; /* 节点结构体 */ typedef struct { int level; // 层级,表示当前处理的物品编号 int profit; // 当前已经获得的最大价值 int weight; // 当前已经使用的背包容量 } Node; /* 优先队列结构体 */ typedef struct { Node *data[MAX_N+1]; // 数据数组 int size; // 队列元素数量 } PriorityQueue; /* 创建优先队列 */ PriorityQueue *create_priority_queue() { PriorityQueue *queue = (PriorityQueue*)malloc(sizeof(PriorityQueue)); queue->size = 0; return queue; } /* 销毁优先队列 */ void destroy_priority_queue(PriorityQueue *queue) { free(queue); } /* 入队 */ void enqueue(PriorityQueue *queue, Node *node) { /* 如果队列已满,则直接返回 */ if (queue->size == MAX_N) { return; } /* 将新节点插入队列尾部 */ int hole = ++queue->size; while (hole > 1 && queue->data[hole/2]->profit < node->profit) { queue->data[hole] = queue->data[hole/2]; hole /= 2; } queue->data[hole] = node; } /* 出队 */ Node *dequeue(PriorityQueue *queue) { /* 如果队列为空,则返回NULL */ if (queue->size == 0) { return NULL; } /* 将队列头节点取出,并将队列尾节点移动到队列头 */ Node *result = queue->data[1]; Node *last = queue->data[queue->size--]; int hole = 1; int child = 2; while (child <= queue->size) { if (child < queue->size && queue->data[child+1]->profit > queue->data[child]->profit) { child++; } if (last->profit >= queue->data[child]->profit) { break; } queue->data[hole] = queue->data[child]; hole = child; child *= 2; } queue->data[hole] = last; return result; } /* 求解01背包问题 */ int knapsack(int n, int w, Item *items) { PriorityQueue *queue = create_priority_queue(); // 创建优先队列 Node *root = (Node*)malloc(sizeof(Node)); // 创建根节点 root->level = 0; root->profit = 0; root->weight = 0; enqueue(queue, root); // 将根节点加入优先队列 int max_profit = 0; // 记录最大价值 while (queue->size > 0) { Node *node = dequeue(queue); // 取出队列头节点 if (node->level >= n) { // 如果已经处理完全部物品,则更新最大价值并跳出循环 max_profit = node->profit; break; } /* 处理左子节点 */ Node *left = (Node*)malloc(sizeof(Node)); left->level = node->level + 1; left->profit = node->profit + items[left->level-1].v; // 加上当前处理的物品的价值 left->weight = node->weight + items[left->level-1].w; // 加上当前处理的物品的重量 if (left->weight <= w && left->profit > max_profit) { // 如果左子节点可以放入背包并且比当前最大价值更优,则将其加入优先队列 enqueue(queue, left); if (left->profit > max_profit) { // 更新最大价值 max_profit = left->profit; } } else { // 否则,释放左子节点的内存 free(left); } /* 处理右子节点 */ Node *right = (Node*)malloc(sizeof(Node)); right->level = node->level + 1; right->profit = node->profit; // 不放当前处理的物品,价值不变 right->weight = node->weight; // 不放当前处理的物品,重量不变 if (bound(right, n, w, items) > max_profit) { // 如果右子节点的上界比当前最大价值更优,则将其加入优先队列 enqueue(queue, right); } else { // 否则,释放右子节点的内存 free(right); } } destroy_priority_queue(queue); // 销毁优先队列 return max_profit; // 返回最大价值 } /* 计算节点的上界 */ int bound(Node *node, int n, int w, Item *items) { if (node->weight >= w) { // 如果当前节点已经超出了背包容量,则不再添加物品 return 0; } int bound = node->profit; // 初始上界为当前节点的价值 int i; for (i = node->level; i < n; i++) { // 从当前节点的下一个物品开始循环 if (node->weight + items[i].w <= w) { // 如果可以放入背包,则加上物品的价值 bound += items[i].v; node->weight += items[i].w; } else { // 否则,加上部分价值即可 int remain = w - node->weight; // 计算剩余空间 bound += remain * (double)items[i].v / items[i].w; // 加上部分价值 break; // 跳出循环 } } return bound; } int main() { int n, w; printf("请输入物品数量和背包容量:\n"); scanf("%d%d", &n, &w); Item items[MAX_N]; printf("请输入每个物品的重量和价值:\n"); int i; for (i = 0; i < n; i++) { scanf("%d%d", &items[i].w, &items[i].v); } int max_profit = knapsack(n, w, items); printf("01背包问题的最大价值为:%d\n", max_profit); return 0; } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值