add
This commit is contained in:
@@ -0,0 +1,176 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define N 3 // 物品数量
|
||||
#define CAPACITY 30 // 背包容量
|
||||
#define MAX_NODES (N * 2) // 估计的最大节点数
|
||||
|
||||
// 物品结构体
|
||||
typedef struct {
|
||||
int weight;
|
||||
int value;
|
||||
} Item;
|
||||
|
||||
// 活结点结构体
|
||||
typedef struct {
|
||||
int level; // 当前节点的层级
|
||||
int profit; // 当前节点的价值
|
||||
int weight; // 当前节点的重量
|
||||
float bound; // 当前节点的上界
|
||||
} Node;
|
||||
|
||||
// 优先队列(最大堆)
|
||||
typedef struct {
|
||||
Node nodes[MAX_NODES];
|
||||
int size;
|
||||
} PriorityQueue;
|
||||
|
||||
// 初始化优先队列
|
||||
void initQueue(PriorityQueue* pq) {
|
||||
pq->size = 0;
|
||||
}
|
||||
|
||||
// 插入节点到优先队列
|
||||
void insert(PriorityQueue* pq, Node node) {
|
||||
if (pq->size == MAX_NODES) {
|
||||
printf("Priority queue is full.\n");
|
||||
return;
|
||||
}
|
||||
int i = pq->size++;
|
||||
while (i > 0 && pq->nodes[(i - 1) / 2].bound < node.bound) {
|
||||
pq->nodes[i] = pq->nodes[(i - 1) / 2];
|
||||
i = (i - 1) / 2;
|
||||
}
|
||||
pq->nodes[i] = node;
|
||||
}
|
||||
|
||||
// 删除并返回优先队列的最大元素
|
||||
Node removeMax(PriorityQueue* pq) {
|
||||
if (pq->size <= 0) {
|
||||
printf("Priority queue is empty.\n");
|
||||
exit(1);
|
||||
}
|
||||
Node max = pq->nodes[0];
|
||||
pq->nodes[0] = pq->nodes[--pq->size];
|
||||
int i = 0;
|
||||
while (2 * i + 1 < pq->size) {
|
||||
int left = 2 * i + 1;
|
||||
int right = 2 * i + 2;
|
||||
int largest = i;
|
||||
if (left < pq->size && pq->nodes[left].bound > pq->nodes[largest].bound)
|
||||
largest = left;
|
||||
if (right < pq->size && pq->nodes[right].bound > pq->nodes[largest].bound)
|
||||
largest = right;
|
||||
if (largest != i) {
|
||||
Node temp = pq->nodes[i];
|
||||
pq->nodes[i] = pq->nodes[largest];
|
||||
pq->nodes[largest] = temp;
|
||||
i = largest;
|
||||
} else break;
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
// 计算节点的上界(bound),这是通过贪心策略估计的最大可能价值
|
||||
float calculateBound(Node u, int n, int W, Item items[]) {
|
||||
if (u.weight >= W) return 0;
|
||||
|
||||
int j = u.level + 1;
|
||||
float bound = u.profit;
|
||||
int totalWeight = u.weight;
|
||||
|
||||
// 从当前节点继续往下选择物品的贪心解(按单位价值排序)
|
||||
while (j < n && totalWeight + items[j].weight <= W) {
|
||||
totalWeight += items[j].weight;
|
||||
bound += items[j].value;
|
||||
j++;
|
||||
}
|
||||
|
||||
if (j < n) {
|
||||
bound += (W - totalWeight) * ((float)items[j].value / items[j].weight);
|
||||
}
|
||||
|
||||
return bound;
|
||||
}
|
||||
|
||||
// 比较函数,用于qsort排序
|
||||
int compareItems(const void* a, const void* b) {
|
||||
Item* itemA = (Item*)a;
|
||||
Item* itemB = (Item*)b;
|
||||
float unitValueA = (float)itemA->value / itemA->weight;
|
||||
float unitValueB = (float)itemB->value / itemB->weight;
|
||||
return (unitValueB - unitValueA) > 0 ? 1 : -1;
|
||||
}
|
||||
|
||||
// 0-1 背包问题的分支限界法
|
||||
int knapsackBranchAndBound(Item items[], int n, int W) {
|
||||
// 按照单位价值对物品进行排序
|
||||
qsort(items, n, sizeof(Item), compareItems);
|
||||
|
||||
PriorityQueue pq;
|
||||
initQueue(&pq);
|
||||
|
||||
// 初始化第一个节点
|
||||
Node u = { -1, 0, 0, 0.0 };
|
||||
insert(&pq, u);
|
||||
|
||||
int maxProfit = 0;
|
||||
|
||||
while (pq.size > 0) {
|
||||
// 取出优先队列中的最大元素
|
||||
u = removeMax(&pq);
|
||||
|
||||
// 如果当前节点的 bound 值不大于最大收益,则剪枝
|
||||
if (u.bound <= maxProfit) continue;
|
||||
|
||||
// 尝试将下一个物品放入背包
|
||||
Node v = u;
|
||||
v.level++;
|
||||
|
||||
if (v.level < n) {
|
||||
// 选择第 v.level 个物品
|
||||
if (v.weight + items[v.level].weight <= W) {
|
||||
v.weight += items[v.level].weight;
|
||||
v.profit += items[v.level].value;
|
||||
if (v.profit > maxProfit) {
|
||||
maxProfit = v.profit;
|
||||
}
|
||||
v.bound = calculateBound(v, n, W, items);
|
||||
if (v.bound > maxProfit) {
|
||||
insert(&pq, v);
|
||||
}
|
||||
}
|
||||
|
||||
// 不选择第 v.level 个物品
|
||||
v = u;
|
||||
v.level++;
|
||||
v.bound = calculateBound(v, n, W, items);
|
||||
if (v.bound > maxProfit) {
|
||||
insert(&pq, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return maxProfit;
|
||||
}
|
||||
|
||||
int main() {
|
||||
// 已经填写的数据
|
||||
int weightArr[N] = {16, 15, 15}; // 每个物品的重量
|
||||
int valueArr[N] = {45, 25, 25}; // 每个物品的价值
|
||||
|
||||
// 初始化物品数组
|
||||
Item items[N];
|
||||
for (int i = 0; i < N; i++) {
|
||||
items[i].weight = weightArr[i];
|
||||
items[i].value = valueArr[i];
|
||||
}
|
||||
|
||||
// 调用分支限界法求解0-1背包问题
|
||||
int maxProfit = knapsackBranchAndBound(items, N, CAPACITY);
|
||||
|
||||
// 输出最大收益
|
||||
printf("Maximum profit: %d\n", maxProfit);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user