桃黑黑反斗战
1.编写求解Hanoi汉诺塔的递归算法代码,输出移动过程,并统计总移动次数。 对不同规模的汉诺塔,给出测试的结果
#include <stdio.h>
#include <time.h>
int moveCount = 0;
void hanoi(int n,char source,char auxiliary,char target) {if (n==1) {moveCount++; printf("Move disk 1 from %c to %c\n", source, target);return;}hanoi(n - 1, source, target, auxiliary);moveCount++;printf("Move disk %d from %c to %c\n", n, source, target);hanoi(n - 1, auxiliary, source, target);
}
int main() {int n;printf("Enter the number of disks: ");scanf("%d", &n);clock_t start_time = clock();hanoi(n, 'A', 'B', 'C');printf("Total moves: %d\n", moveCount);clock_t end_time = clock();double time_taken = ((double)(end_time - start_time)) / CLOCKS_PER_SEC;printf("Total moves: %d\n", moveCount);printf("Time taken: %f seconds\n", time_taken);double theoretical_moves = (1 << n) - 1; printf("Theoretical moves (2^%d-1): %f\n", n, theoretical_moves);return 0;
}
2.编写程序实现2个有序数组的合并,并输出基本操作(比较、移动)的次数。
#include <stdio.h>
void merge(int a[], int n1, int b[], int n2, int c[], int *comp, int *move);
int main() {int n1, n2;printf("请输入第一个数组的大小: ");scanf("%d", &n1);int a[n1];printf("请输入第一个数组的元素: ");for (int i = 0; i < n1; i++) {scanf("%d", &a[i]);}printf("请输入第二个数组的大小: ");scanf("%d", &n2);int b[n2];printf("请输入第二个数组的元素: ");for (int i = 0; i < n2; i++) {scanf("%d", &b[i]);}int c[n1 + n2];int comp = 0, move = 0;merge(a, n1, b, n2, c, &comp, &move);printf("合并后的数组: ");for (int i = 0; i < n1 + n2; i++) {printf("%d ", c[i]);}printf("\n");printf("比较操作次数: %d\n", comp);printf("移动操作次数: %d\n", move);return 0;
}
void merge(int a[], int n1, int b[], int n2, int c[], int *comp, int *move) {int i = 0, j = 0, k = 0;while (i < n1 && j < n2) {(*comp)++; if (a[i] < b[j]) {c[k++] = a[i++]; (*move)++;} else {c[k++] = b[j++]; (*move)++;}}while (i < n1) {c[k++] = a[i++]; (*move)++;}while (j < n2) {c[k++] = b[j++]; (*move)++;}
}
3.使用蛮力法计算平面上最接近的两点之间的距离,理解O(n^2)时间复杂度的影响
#include <iostream>
#include <vector>
#include <cmath>
#include <limits>
#include <cstdlib>
#include <ctime>
using namespace std;
struct Point {double x, y;Point(double a, double b) {x = a;y = b;}
};
int main() {srand(time(0)); int numPoints = 10; vector<Point> points; for (int i = 0; i < numPoints; i++) {double x = rand() % 100; double y = rand() % 100;points.push_back(Point(x, y)); }cout << "随机生成的点:" << endl; for (size_t i = 0; i < points.size(); i++) { cout << "(" << points[i].x << ", " << points[i].y << ")" << endl;}double minDist = numeric_limits<double>::max(); for (int i = 0; i < numPoints; i++) {for (int j = i + 1; j < numPoints; j++) { double dx = points[i].x - points[j].x;double dy = points[i].y - points[j].y;double dist = sqrt(dx * dx + dy * dy); if (dist < minDist) {minDist = dist;}}}cout << "最近两点之间的最短距离:" << minDist << endl;return 0;
}
4.求有序数组中两个数的和等于目标值
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int* twoSum(int* nums, int numsSize, int target, int* returnSize) {int left = 0;int right = numsSize - 1;int* result = (int*)malloc(2 * sizeof(int));if (result == NULL) {return NULL;}while (left < right) {int sum = nums[left] + nums[right];if (sum == target) {result[0] = left;result[1] = right;*returnSize = 2;return result;} else if (sum < target) {left++;} else {right--;}}*returnSize = 0;free(result);return NULL;
}
void parseInput(const char* input, int** nums, int* numsSize, int* target) {char* temp = strdup(input);char* token = strtok(temp, "=[], ");token = strtok(NULL, "=[], ");*numsSize = 0;while (token != NULL && strcmp(token, "target") != 0) {(*numsSize)++;token = strtok(NULL, "=[], ");}*nums = (int*)malloc(*numsSize * sizeof(int));if (*nums == NULL) {printf("内存分配失败\n");exit(1);}token = strtok(temp, "=[], ");token = strtok(NULL, "=[], ");for (int i = 0; i < *numsSize; i++) {(*nums)[i] = atoi(token);token = strtok(NULL, "=[], ");}token = strtok(NULL, "=[], ");*target = atoi(token);free(temp);
}
int main() {char input[1000];printf("请按照 nums=[1, 3, 5, 7, 9], target=10 的格式输入: ");fgets(input, sizeof(input), stdin);input[strcspn(input, "\n")] = 0; int* nums;int numsSize;int target;parseInput(input, &nums, &numsSize, &target);int returnSize;int* result = twoSum(nums, numsSize, target, &returnSize);if (result != NULL) {printf("[%d, %d]\n", result[0], result[1]);free(result);} else {printf("未找到符合条件的两个数\n");}free(nums);return 0;
}
5.给定一组物品,每个物品有一个重量和一个价值。背包有一个最大承重限制。目标是从这些物品中选择一部分装入背包,使得背包中物品的总价值最大。与0/1背包问题不同,分数背包问题允许将物品分割成任意大小(即可以选择物品的一部分装入背包)。//输入:物品数量 n、每个物品的重量和价值 、背包的最大承重W
#include <stdio.h>
#include <stdlib.h>typedef struct {int weight;int value;double ratio;
} Item;
int compare(const void *a, const void *b) {Item *itemA = (Item *)a;Item *itemB = (Item *)b;if (itemA->ratio < itemB->ratio)return 1;else if (itemA->ratio > itemB->ratio)return -1;return 0;
}
double fractionalKnapsack(int n, Item items[], int capacity) {for (int i = 0; i < n; i++) {items[i].ratio = (double)items[i].value / items[i].weight;}qsort(items, n, sizeof(Item), compare);double totalValue = 0.0;int currentCapacity = capacity;for (int i = 0; i < n; i++) {if (currentCapacity >= items[i].weight) {totalValue += items[i].value;currentCapacity -= items[i].weight;} else {totalValue += currentCapacity * items[i].ratio;break;}}return totalValue;
}
int main() {int n, capacity;printf("请输入物品的数量: ");scanf("%d", &n);Item *items = (Item *)malloc(n * sizeof(Item));if (items == NULL) {printf("内存分配失败\n");return 1;}printf("请依次输入每个物品的重量和价值:\n");for (int i = 0; i < n; i++) {scanf("%d %d", &items[i].weight, &items[i].value);}printf("请输入背包的最大承重: ");scanf("%d", &capacity);double maxValue = fractionalKnapsack(n, items, capacity);printf("背包中物品的最大总价值为: %.2f\n", maxValue);free(items);return 0;
}
6.在区间调度问题中,给定 n 个作业,每个作业由一个时间区间 [s_i, f_i](s_i 为开始时间,f_i 为结束时间)表示。每个作业互不兼容(即不能同时运行两个作业)。目标是在不重叠的情况下安排最多的作业。
#include <stdio.h>
#include <stdlib.h>
typedef struct {int start;int end;int index;
} Job;
int compare(const void *a, const void *b) {Job *jobA = (Job *)a;Job *jobB = (Job *)b;return jobA->end - jobB->end;
}
int main() {int n;printf("请输入任务数: ");scanf("%d", &n);Job *jobs = (Job *)malloc(n * sizeof(Job));if (jobs == NULL) {printf("内存分配失败\n");return 1;}// 输入每个作业的开始和结束时间for (int i = 0; i < n; i++) {printf("请输入第 %d 个作业的开始时间和结束时间: ", i + 1);scanf("%d %d", &jobs[i].start, &jobs[i].end);jobs[i].index = i + 1;}// 按结束时间排序qsort(jobs, n, sizeof(Job), compare);int selectedJobs[100];int count = 0;// 选择第一个作业selectedJobs[count++] = jobs[0].index;int prevEnd = jobs[0].end;// 贪心选择作业for (int i = 1; i < n; i++) {if (jobs[i].start >= prevEnd) {selectedJobs[count++] = jobs[i].index;prevEnd = jobs[i].end;}}// 输出结果printf("选出的作业个数: %d\n", count);printf("选出的作业序列: ");for (int i = 0; i < count; i++) {printf("%d ", selectedJobs[i]);}printf("\n");free(jobs);return 0;
}
7.
7.1选择邻接矩阵或邻接表作为图的存储结构.使用 Prim 算法求解最小生成树。输出最小生成树的总权值和具体选取的边。
#include <stdio.h>
#include <limits.h>
#include <stdlib.h> // 添加这一行
// 找到距离最小生成树最近且未被包含的顶点
int minKey(int key[], int mstSet[], int V) {int min = INT_MAX, min_index;for (int v = 0; v < V; v++) {if (mstSet[v] == 0 && key[v] < min) {min = key[v];min_index = v;}}return min_index;
}
// 打印最小生成树
void printMST(int parent[], int **graph, int V) {int total_weight = 0;printf("Edge \tWeight\n");for (int i = 1; i < V; i++) {printf("%d - %d \t%d \n", parent[i], i, graph[i][parent[i]]);total_weight += graph[i][parent[i]];}printf("Total weight of MST: %d\n", total_weight);
}
// Prim 算法实现
void primMST(int **graph, int V) {int *parent = (int *)malloc(V * sizeof(int)); // 存储最小生成树中每个顶点的父节点int *key = (int *)malloc(V * sizeof(int)); // 存储每个顶点到最小生成树的最小权值int *mstSet = (int *)malloc(V * sizeof(int)); // 标记顶点是否已被包含在最小生成树中// 初始化所有顶点的 key 值为无穷大,mstSet 为 falsefor (int i = 0; i < V; i++) {key[i] = INT_MAX;mstSet[i] = 0;}// 从顶点 0 开始构建最小生成树key[0] = 0;parent[0] = -1; // 顶点 0 是根节点,没有父节点// 构建最小生成树,直到包含所有顶点for (int count = 0; count < V - 1; count++) {// 找到距离最小生成树最近且未被包含的顶点int u = minKey(key, mstSet, V);// 将该顶点标记为已包含在最小生成树中mstSet[u] = 1;// 更新与该顶点相邻且未被包含的顶点的 key 值和父节点for (int v = 0; v < V; v++) {if (graph[u][v] && mstSet[v] == 0 && graph[u][v] < key[v]) {parent[v] = u;key[v] = graph[u][v];}}}// 打印最小生成树printMST(parent, graph, V);// 释放动态分配的内存free(parent);free(key);free(mstSet);
}
int main() {int V;printf("请输入图的顶点数量: ");scanf("%d", &V);// 动态分配邻接矩阵的内存int **graph = (int **)malloc(V * sizeof(int *));for (int i = 0; i < V; i++) {graph[i] = (int *)malloc(V * sizeof(int));}printf("请输入图的邻接矩阵(%d x %d):\n", V, V);for (int i = 0; i < V; i++) {for (int j = 0; j < V; j++) {scanf("%d", &graph[i][j]);}}// 调用 Prim 算法求解最小生成树primMST(graph, V);// 释放邻接矩阵的内存for (int i = 0; i < V; i++) {free(graph[i]);}free(graph);return 0;
}
7.2进阶:采用优先队列(堆优化)版本的Prim算法,提高效率。
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
// 定义一个结构体来表示图的边
typedef struct {int vertex;int weight;
} Edge;
// 定义一个结构体来表示优先队列的元素
typedef struct {int vertex;int key;
} QueueElement;
// 交换两个队列元素
void swap(QueueElement *a, QueueElement *b) {QueueElement temp = *a;*a = *b;*b = temp;
}
// 最小堆化
void minHeapify(QueueElement *heap, int *pos, int n, int i) {int smallest = i;int left = 2 * i + 1;int right = 2 * i + 2;if (left < n && heap[left].key < heap[smallest].key)smallest = left;if (right < n && heap[right].key < heap[smallest].key)smallest = right;if (smallest != i) {// 更新位置数组pos[heap[smallest].vertex] = i;pos[heap[i].vertex] = smallest;swap(&heap[smallest], &heap[i]);minHeapify(heap, pos, n, smallest);}
}
// 从堆中提取最小元素
QueueElement extractMin(QueueElement *heap, int *pos, int *n) {QueueElement root = heap[0];QueueElement last = heap[*n - 1];// 将最后一个元素移到根节点heap[0] = last;// 更新位置数组pos[root.vertex] = *n - 1;pos[last.vertex] = 0;// 减小堆的大小(*n)--;// 最小堆化minHeapify(heap, pos, *n, 0);return root;
}
// 减小某个顶点的 key 值
void decreaseKey(QueueElement *heap, int *pos, int n, int v, int key) {int i = pos[v];heap[i].key = key;while (i && heap[i].key < heap[(i - 1) / 2].key) {// 更新位置数组pos[heap[i].vertex] = (i - 1) / 2;pos[heap[(i - 1) / 2].vertex] = i;swap(&heap[i], &heap[(i - 1) / 2]);i = (i - 1) / 2;}
}
// 检查顶点是否在堆中
int isInHeap(int *pos, int v, int n) {return pos[v] < n;
}// 打印最小生成树
void printMST(int parent[], int **graph, int V) {int total_weight = 0;printf("Edge \tWeight\n");for (int i = 1; i < V; i++) {printf("%d - %d \t%d \n", parent[i], i, graph[i][parent[i]]);total_weight += graph[i][parent[i]];}printf("Total weight of MST: %d\n", total_weight);
}
// 堆优化的 Prim 算法
void primMST(int **graph, int V) {int *parent = (int *)malloc(V * sizeof(int)); // 存储最小生成树中每个顶点的父节点int *key = (int *)malloc(V * sizeof(int)); // 存储每个顶点到最小生成树的最小权值int *pos = (int *)malloc(V * sizeof(int)); // 存储每个顶点在堆中的位置QueueElement *heap = (QueueElement *)malloc(V * sizeof(QueueElement));// 初始化所有顶点的 key 值为无穷大,parent 为 -1for (int i = 0; i < V; i++) {key[i] = INT_MAX;parent[i] = -1;pos[i] = i;heap[i].vertex = i;heap[i].key = INT_MAX;}// 从顶点 0 开始构建最小生成树key[0] = 0;heap[0].key = 0;int heapSize = V;while (heapSize > 0) {// 提取最小 key 值的顶点QueueElement minElement = extractMin(heap, pos, &heapSize);int u = minElement.vertex;// 遍历所有相邻顶点for (int v = 0; v < V; v++) {if (graph[u][v] && isInHeap(pos, v, heapSize) && graph[u][v] < key[v]) {key[v] = graph[u][v];parent[v] = u;decreaseKey(heap, pos, heapSize, v, key[v]);}}}// 打印最小生成树printMST(parent, graph, V);// 释放动态分配的内存free(parent);free(key);free(pos);free(heap);
}
int main() {int V;printf("请输入图的顶点数量: ");scanf("%d", &V);// 动态分配邻接矩阵的内存int **graph = (int **)malloc(V * sizeof(int *));for (int i = 0; i < V; i++) {graph[i] = (int *)malloc(V * sizeof(int));}printf("请输入图的邻接矩阵(%d x %d):\n", V, V);for (int i = 0; i < V; i++) {for (int j = 0; j < V; j++) {scanf("%d", &graph[i][j]);}}// 调用堆优化的 Prim 算法求解最小生成树primMST(graph, V);// 释放邻接矩阵的内存for (int i = 0; i < V; i++) {free(graph[i]);}free(graph);return 0;
}
8.[逆序数算法】编写一个函数 countInversions
,用于计算整数数组中的逆序对数。逆序对是指满足条件 i < j
且 arr[i] > arr[j]
的数对 (i, j)
。
#include <stdio.h>
#include <stdlib.h>
int merge(int arr[], int left, int mid, int right) {int n1 = mid - left + 1;int n2 = right - mid;int L[n1], R[n2];int i, j, k;int inversions = 0;for (i = 0; i < n1; i++)L[i] = arr[left + i];for (j = 0; j < n2; j++)R[j] = arr[mid + 1 + j];i = 0; j = 0; k = left; while (i < n1 && j < n2) {if (L[i] <= R[j]) {arr[k] = L[i];i++;} else {arr[k] = R[j];j++;inversions += (n1 - i);}k++;}while (i < n1) {arr[k] = L[i];i++;k++;}while (j < n2) {arr[k] = R[j];j++;k++;}return inversions;
}
int mergeSort(int arr[], int left, int right) {int inversions = 0;if (left < right) {int mid = left + (right - left) / 2;inversions += mergeSort(arr, left, mid);inversions += mergeSort(arr, mid + 1, right);inversions += merge(arr, left, mid, right);}return inversions;
}
int countInversions(int arr[], int n) {return mergeSort(arr, 0, n - 1);
}int main() {char input[1000];int arr[1000];int n = 0;fgets(input, sizeof(input), stdin);int i = 1;while (input[i] != '\0') {if (input[i] == ']') {break;}if (input[i] != ' ' && input[i] != ',') {int num = 0;int sign = 1;if (input[i] == '-') {sign = -1;i++;}while (input[i] >= '0' && input[i] <= '9') {num = num * 10 + (input[i] - '0');i++;}arr[n++] = sign * num;} else {i++;}}int inversions = countInversions(arr, n);printf(" %d\n", inversions);return 0;
}
9.实现 Median of Medians 算法,用于在无序数组中找出第 k 小的元素。
#include <stdio.h>
#include <stdlib.h>
// 交换函数
void swap(int *a, int *b) {int temp = *a;*a = *b;*b = temp;
}
// 插入排序(用于小数组排序和验证用)
void insertionSort(int arr[], int left, int right) {for (int i = left + 1; i <= right; i++) {int key = arr[i];int j = i - 1;while (j >= left && arr[j] > key) {arr[j + 1] = arr[j];j--;}arr[j + 1] = key;}
}
// 获取一组的中位数
int getMedian(int arr[], int left, int right) {insertionSort(arr, left, right);return arr[(left + right) / 2];
}
// 分区操作
int partition(int arr[], int left, int right, int pivot) {int i;for (i = left; i <= right; i++) {if (arr[i] == pivot) break;}swap(&arr[i], &arr[right]);int storeIndex = left;for (i = left; i < right; i++) {if (arr[i] < pivot) {swap(&arr[i], &arr[storeIndex]);storeIndex++;}}swap(&arr[storeIndex], &arr[right]);return storeIndex;
}
// 主算法:Median of Medians
int selectKth(int arr[], int left, int right, int k) {int n = right - left + 1;if (n <= 5) {insertionSort(arr, left, right);return arr[left + k - 1];}int medianCount = (n + 4) / 5;int *medians = (int *)malloc(medianCount * sizeof(int));for (int i = 0; i < medianCount; i++) {int subLeft = left + i * 5;int subRight = subLeft + 4;if (subRight > right) subRight = right;medians[i] = getMedian(arr, subLeft, subRight);}int medOfMed = selectKth(medians, 0, medianCount - 1, (medianCount + 1) / 2);free(medians);int pivotIndex = partition(arr, left, right, medOfMed);int rank = pivotIndex - left + 1;if (k == rank)return arr[pivotIndex];else if (k < rank)return selectKth(arr, left, pivotIndex - 1, k);elsereturn selectKth(arr, pivotIndex + 1, right, k - rank);
}
// 主函数
int main() {int n, k;printf("请输入数组长度 n:");scanf("%d", &n);if (n <= 0) {printf("错误:数组长度必须为正数!\n");return 1;}int *arr = (int *)malloc(n * sizeof(int));int *arrCopy = (int *)malloc(n * sizeof(int));printf("请输入 %d 个整数:\n", n);for (int i = 0; i < n; i++) {scanf("%d", &arr[i]);arrCopy[i] = arr[i]; // 复制一份用于验证}printf("请输入要查找的第 k 小元素 (1 ~ %d):", n);scanf("%d", &k);if (k < 1 || k > n) {printf("错误:k 值不合法!\n");free(arr);free(arrCopy);return 1;}int result = selectKth(arr, 0, n - 1, k);printf("第 %d 小的元素是:%d\n", k, result);// 验证部分insertionSort(arrCopy, 0, n - 1);int expected = arrCopy[k - 1];if (result == expected) {printf("验证结果:正确\n");} else {printf("验证结果:错误 (应为 %d)\n", expected);}free(arr);free(arrCopy);return 0;
}
10.掌握动态规划求解0-1背包问题的基本思想与实现步骤。
# 1.给定若干个物品,每个物品有重量和价值,背包容量为一定的正整数。
# 2.实现一个动态规划算法,求解在给定容量下,能够装入背包的最大总价值。
# 3.输出最终最大价值,以及用于构造该最优值的物品组合(可选)。
# 4.显示动态规划中构建的二维数组 dp[i][j] 的过程(物品编号 i、容量 j)。
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
// 打印二维数组 dp
void printDP(const vector< vector<int> >& dp) {for (int i = 0; i < dp.size(); i++) {for (int j = 0; j < dp[i].size(); j++) {cout << dp[i][j] << " ";}cout << endl;}cout << endl;
}
// 回溯找出选择的物品
vector<int> findSelectedItems(const vector< vector<int> >& dp, const vector<int>& weights, const vector<int>& values, int n, int capacity) {vector<int> selectedItems;int i = n, j = capacity;while (i > 0 && j > 0) {if (dp[i][j] != dp[i - 1][j]) {selectedItems.push_back(i);j -= weights[i - 1];}i--;}vector<int> reversedItems;for (int k = selectedItems.size() - 1; k >= 0; k--) {reversedItems.push_back(selectedItems[k]);}return reversedItems;
}
int main() {int n; // 物品数量int capacity; // 背包容量cout << "请输入物品数量: ";cin >> n;cout << "请输入背包容量: ";cin >> capacity;vector<int> weights(n);vector<int> values(n);cout << "请依次输入每个物品的 编号 重量 价值(格式:编号 重量 价值):" << endl;for (int i = 0; i < n; i++) {int id;cout << "物品 " << i + 1 << ": ";cin >> id >> weights[i] >> values[i];}// 初始化二维数组 dpvector< vector<int> > dp(n + 1);for (int i = 0; i <= n; i++) {dp[i].resize(capacity + 1, 0);}// 动态规划过程for (int i = 1; i <= n; i++) {for (int j = 0; j <= capacity; j++) {if (j < weights[i - 1]) {dp[i][j] = dp[i - 1][j];} else {dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weights[i - 1]] + values[i - 1]);}}// 输出每一步的二维数组变化情况cout << "Step " << i << ":" << endl;printDP(dp);}// 输出最大价值int maxValue = dp[n][capacity];cout << "最大价值: " << maxValue << endl;// 找出选择的物品vector<int> selectedItems = findSelectedItems(dp, weights, values, n, capacity);cout << "选择的物品编号: ";for (int i = 0; i < selectedItems.size(); i++) {cout << selectedItems[i] << " ";}cout << endl;return 0;
}
11.编写程序,使用回溯法输出给定整数序列的所有排列,例如输入{1,2,3}
#include <iostream>
#include <vector>
#include <algorithm>
#include <sstream>
using namespace std;
// 回溯函数生成全排列
void backtrack(vector<int>& nums, vector<int>& path, vector<bool>& used) {if (path.size() == nums.size()) {for (int i = 0; i < path.size(); ++i) {cout << path[i] << " ";}cout << endl;return;}for (int i = 0; i < nums.size(); ++i) {if (!used[i]) {used[i] = true;path.push_back(nums[i]);backtrack(nums, path, used);path.pop_back();used[i] = false;}}
}
int main() {string input;getline(cin, input);istringstream iss(input);vector<int> nums;int num;while (iss >> num) {nums.push_back(num);}if (nums.empty()) {cout << "输入不能为空!" << endl;return 1;}vector<int> path;vector<bool> used(nums.size(), false);backtrack(nums, path, used);return 0;
}
12、分支限界发求解0-1背包问题//给定一组物品,每个物品有重量wi和价值vi,以及一个容量为C的背包。要求选择物品的子集,使得总重量不超过背包容量,且总价值最大。每个物品只能选或不选(0-1属性)。
#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
// 物品结构体
struct Item {int index;int weight;int value;double ratio;Item(int idx, int w, int v) : index(idx), weight(w), value(v) {ratio = (double)v / w;}
};
// 分支限界树节点结构体
struct Node {int level;int value;int weight;double bound;vector<int> path;bool operator<(const Node& other) const {return bound < other.bound;}
};
// 上界计算函数
double computeBound(Node u, int n, int W, const vector<Item>& items) {if (u.weight >= W) return 0;double bound = u.value;int totalWeight = u.weight;for (int i = u.level; i < n; ++i) {if (totalWeight + items[i].weight <= W) {totalWeight += items[i].weight;bound += items[i].value;} else {int remain = W - totalWeight;bound += remain * items[i].ratio;break;}}return bound;
}
// 主算法
int knapsackBranchBound(int W, vector<Item>& items, vector<int>& bestPath) {sort(items.begin(), items.end(), [](const Item& a, const Item& b) {return a.ratio > b.ratio;});priority_queue<Node> pq;int maxValue = 0;Node root = {0, 0, 0, 0.0, {}};root.bound = computeBound(root, items.size(), W, items);pq.push(root);while (!pq.empty()) {Node current = pq.top(); pq.pop();if (current.bound <= maxValue || current.level == items.size())continue;// 包含当前物品Node include = current;Item item = items[current.level];include.level++;include.weight += item.weight;include.value += item.value;include.path.push_back(item.index);include.bound = computeBound(include, items.size(), W, items);if (include.weight <= W && include.value > maxValue) {maxValue = include.value;bestPath = include.path;}if (include.bound > maxValue)pq.push(include);// 不包含当前物品Node exclude = current;exclude.level++;exclude.bound = computeBound(exclude, items.size(), W, items);if (exclude.bound > maxValue)pq.push(exclude);}return maxValue;
}
int main() {int n, W;cout << "请输入物品数量:";cin >> n;cout << "请输入背包容量:";cin >> W;vector<int> weights(n), values(n);cout << "请输入所有物品的重量:" << endl;for (int i = 0; i < n; ++i) {cin >> weights[i];}cout << "请输入所有物品的价值:" << endl;for (int i = 0; i < n; ++i) {cin >> values[i];}vector<Item> items;for (int i = 0; i < n; ++i) {items.emplace_back(i + 1, weights[i], values[i]);}vector<int> selectedItems;int maxValue = knapsackBranchBound(W, items, selectedItems);cout << "\n最大价值:" << maxValue << endl;cout << "选择物品:" << endl;for (int idx : selectedItems) {cout << " 物品" << idx << "(重量" << weights[idx - 1]<< ",价值" << values[idx - 1] << ")" << endl;}return 0;
}