#include <stdio.h>
#include <stdlib.h>
#define MAX 100
typedef struct {
int level; // 当前层次
int weight; // 当前重量
int value; // 当前价值
int bound; // 上界
int include[MAX]; // 是否包含某物品
} Node;
typedef struct {
Node data[MAX];
int size;
} PriorityQueue;
void swap(Node *a, Node *b) {
Node temp = *a;
*a = *b;
*b = temp;
}
void push(PriorityQueue *pq, Node node) {
pq->data[pq->size++] = node;
int i = pq->size - 1;
while (i > 0 && pq->data[i].bound > pq->data[(i - 1) / 2].bound) {
swap(&pq->data[i], &pq->data[(i - 1) / 2]);
i = (i - 1) / 2;
}
}
Node pop(PriorityQueue *pq) {
Node top = pq->data[0];
pq->data[0] = pq->data[--pq->size];
int i = 0;
while (2 * i + 1 < pq->size) {
int j = 2 * i + 1;
if (j + 1 < pq->size && pq->data[j + 1].bound > pq->data[j].bound) {
j++;
}
if (pq->data[i].bound >= pq->data[j].bound) {
break;
}
swap(&pq->data[i], &pq->data[j]);
i = j;
}
return top;
}
int bound(Node u, int n, int C, int weights[], int values[]) {
if (u.weight >= C) {
return 0;
}
int profit_bound = u.value;
int j = u.level + 1;
int totweight = u.weight;
while (j < n && totweight + weights[j] <= C) {
totweight += weights[j];
profit_bound += values[j];
j++;
}
if (j < n) {
profit_bound += (C - totweight) * values[j] / weights[j];
}
return profit_bound;
}
void knapsack(int n, int C, int weights[], int values[]) {
PriorityQueue pq;
pq.size = 0;
Node u, v;
v.level = -1;
v.weight = 0;
v.value = 0;
v.bound = bound(v, n, C, weights, values);
push(&pq, v);
int maxValue = 0;
int bestInclude[MAX] = {0};
while (pq.size > 0) {
v = pop(&pq);
if (v.bound > maxValue) {
u.level = v.level + 1;
u.weight = v.weight + weights[u.level];
u.value = v.value + values[u.level];
for (int i = 0; i < u.level; i++) {
u.include[i] = v.include[i];
}
u.include[u.level] = 1;
if (u.weight <= C && u.value > maxValue) {
maxValue = u.value;
for (int i = 0; i < n; i++) {
bestInclude[i] = u.include[i];
}
}
u.bound = bound(u, n, C, weights, values);
if (u.bound > maxValue) {
push(&pq, u);
}
u.weight = v.weight;
u.value = v.value;
for (int i = 0; i < u.level; i++) {
u.include[i] = v.include[i];
}
u.include[u.level] = 0;
u.bound = bound(u, n, C, weights, values);
if (u.bound > maxValue) {
push(&pq, u);
}
}
}
printf("%d\n", maxValue);
printf("(");
for (int i = 0; i < n; i++) {
printf("%d", bestInclude[i]);
if (i < n - 1) {
printf(",");
}
}
printf(")\n");
}
int main() {
int n, C;
scanf("%d", &n);
scanf("%d", &C);
int weights[MAX], values[MAX];
for (int i = 0; i < n; i++) {
scanf("%d %d", &weights[i], &values[i]);
}
knapsack(n, C, weights, values);
return 0;
}
-
定义节点和优先队列结构:
Node
结构体包含当前层次、当前重量、当前价值、上界和包含物品的布尔数组。PriorityQueue
结构体包含节点数组和大小。
-
队列操作:
push
函数将节点加入优先队列,按上界值进行排序。pop
函数从优先队列中取出上界值最大的节点。swap
函数交换两个节点。
-
上界计算:
bound
函数计算节点的上界值,作为优先级的依据。
-
主函数:
- 输入物品数量
n
和背包容量C
。 - 输入每个物品的重量和价值。
- 初始化优先队列和根节点。
- 使用优先队列式分支限界法进行搜索:
- 从优先队列中取出节点。
- 生成左子节点(包含当前物品)并检查其重量和价值是否满足条件。
- 如果左子节点满足条件且其价值大于当前最大价值,则更新最大价值和最佳包含状态。
- 计算左子节点的上界值并将其加入优先队列。
- 生成右子节点(不包含当前物品)并计算其上界值,将其加入优先队列。
- 输出最大价值和最佳包含状态。
- 输入物品数量