This commit is contained in:
2026-06-15 09:00:38 +08:00
parent fec66377d5
commit 4640c5e02b
191 changed files with 6046 additions and 0 deletions
+90
View File
@@ -0,0 +1,90 @@
#include <stdio.h>
#include <stdbool.h>
#define CAPACITY 30
#define N 3
#define QUEUE_SIZE 100 // 定义队列的最大容量(静态分配)
typedef struct {// 定义节点结构体
int level; // 当前节点所在的层数(即考虑第几个物品)
int weight; // 当前已装入物品的总重量
int value; // 当前已获得的总价值
bool items[N]; // 布尔数组,记录每个物品是否被选择
} Node;
// 定义队列结构体,使用数组模拟队列
typedef struct {
Node liveList[QUEUE_SIZE]; // 队列的存储数组
int front, rear; // 队列的头部和尾部指针
} Queue;
// 初始化队列,设置front为0,rear为-1表示空队列
void initQueue(Queue* queue) {
queue->front = 0; queue->rear = -1;
}
// 检查队列是否为空,如果front大于rear则为空
int isEmpty(Queue* queue) {
return queue->front > queue->rear;
}
// 向队列中添加元素,使用前置自增保证新元素放置在正确位置
void insertQueue(Queue* queue, Node item) {
queue->liveList[++(queue->rear)] = item;
}
// 从队列中移除并返回元素,如果队列为空则返回一个空节点
Node popQueue(Queue* queue) {
if (isEmpty(queue)) {
static Node emptyNode = {-1, -1, -1, {false}};
return emptyNode;
}
return queue->liveList[(queue->front)++];
}
// 使用广度优先搜索(BFS)解决01背包问题
void bag01bfs(Queue* queue, int weightArr[], int value[], int n, int maxWeight,
int* maxValue, bool bestItems[]) {
// 创建初始节点(level=0weight=0value=0items全为false),并将其加入队列
Node node = {0, 0, 0, {false}};
insertQueue(queue, node);
while (!isEmpty(queue)) { // 开始广度优先搜索
Node u = popQueue(queue); // 取出队列中的第一个节点
// 如果遇到空节点,跳过本次循环
if (u.level == -1) continue;
if (u.level == n) { // 如果到达最后一层(所有物品都考虑完毕)
if (u.value > *maxValue) { // 更新最大价值和最优解
*maxValue = u.value;
for (int i = 0; i < N; ++i)
bestItems[i] = u.items[i];
}
continue;
}
// 分支:包含当前物品的情况
if (u.weight + weightArr[u.level] <= maxWeight) {
// 创建新节点v,代表选择了当前物品的情况
Node v = {u.level + 1, u.weight + weightArr[u.level], u.value + value[u.level]};
for (int i = 0; i < N; ++i)
v.items[i] = u.items[i];
v.items[u.level] = true;
insertQueue(queue, v);
}
// 分支:不包含当前物品的情况
Node w = {u.level + 1, u.weight, u.value};
for (int i = 0; i < N; ++i)
w.items[i] = u.items[i];
insertQueue(queue, w);
}
}
int main() {
// 定义每个物品的重量和价值
int weightArr[N] = {16, 15, 15}; // 每个物品的重量
int value[N] = {45, 25, 25}; // 每个物品的价值
int maxValue = 0; // 最大价值
bool bestItems[N] = {false}; // 记录最优解的物品选择情况
Queue queue;
initQueue(&queue); // 初始化队列
// 调用bag01bfs函数解决背包问题
bag01bfs(&queue, weightArr, value, N, CAPACITY, &maxValue, bestItems);
// 输出结果
printf("最大价值是 %d\n", maxValue);
printf("选择的物品:");
for (int i = 0; i < N; ++i) {
if (bestItems[i])
printf("%d ", i + 1); // 输出物品编号(从1开始)
}
return 0;
}
Binary file not shown.
+176
View File
@@ -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;
}
Binary file not shown.