桃黑黑反斗战

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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值