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 为 false
for (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 为 -1
for (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);
else
return 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];
}
// 初始化二维数组 dp
vector< 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;
}
1万+

被折叠的 条评论
为什么被折叠?



