蛮力法 解决0/1背包问题

实验项目1 蛮力法

实验题目 使用蛮力法解决0/1背包问题。

问题描述:给定n个重量(weight)为{w1, w2, … ,wn}价值(key)为{v1, v2, … ,vn}的物品和一个容量为C(contain)的背包,求这些物品中的一个最有价值的子集,且要能够装到背包中。
eg:示例:
背包容量C=15kg
物品1:重量2kg,价值2$
物品2:重量12kg,价值4$
物品3:重量1kg,价值2$
物品4:重量1kg,价值1$
物品5:重量4kg,价值10$

img

实验目的

  1. 理解算法的时间复杂度;
  2. 熟练设计和生成问题的解空间:设计一种穷举策略将物品装入背包的各种装法都找出来,并能够在计算机中存储和表示。
  3. 理解蛮力法的局限性;
  4. 实验要求
  5. 掌握用递归或循环生成n个元素的全部子集的算法设计方法;

按上图示例数据求解出问题的一个最优解:装入哪几个物品价值最大,总重量和总价值各是多少?

蛮力法的主要框架

// 辅助数组,防止递归死循环
int visited[5] = { 0 };
// w容量,key价值,len:weight数组长度 depth 深度
void backpack(int w, int* weight, int* key, int len, int depth, int tempSum) {
    // 如果到达物品数组的末尾 地柜出口
    if (depth == len) {
        return;
    }
    // 不选择当前物品
    visited[depth] = 0;
    backpack(w, weight, key, len, depth + 1, tempSum);
    // 如果能选择当前物品(背包容量足够)
    visited[depth] = 1; // 选择当前物品
    backpack(w - arr[depth], weight, key, len, depth + 1, tempSum + key[depth]); // 递归调用
}

不难看出使用的是递归的方式

算法代码

#include<stdio.h>

// 辅助数组,防止递归死循环
int visited[5] = { 0 };
// 寻找最大值
int sumMax = 0;
//
int weightSum = 0;
// 寻找最大值对应装填方式
int method[5] = { 0 };
int capacity = 15; // 背包容量
int count = 0;
//判断容量是否合理
int LessCapacity(int len,const int* arr){
    int sumWeight = 0;
    for (int i = 0; i < len; ++i) {
        if(visited[i] == 1)
        sumWeight += arr[i];
    }
//    满足小于等于15 为 1
    return sumWeight<=capacity ? 1:0;
}
// 遍历当前状态,更新最大价值和装填方式
void Traverse(int* arr,  int len, int tempSum, int depth) {
    printf("--------------------------------------------\n");
    int weight = 0;
    // 打印当前状态
    printf("重量: ");
    for (int i = 0; i < len; ++i) {
        printf("%d  ", arr[i]);
    }
    printf("\n");
    printf("选择: ");
    for (int i = 0; i < len; i++) {
        printf("%d  ", visited[i]);
        if(visited[i]){
            weight+=arr[i];
        }
    }
    printf("\n");
    printf("当前总重量: %d\n", weight);
    printf("当前总价值: %d\n", tempSum);
    if(weight>capacity){
        printf("该情况不符合要求!\n");
    }else{
        printf("该情况符合要求!\n");
    }
    printf("--------------------------------------------\n\n");
    // 如果当前价值大于已知的最大价值,则更新最大价值和method数组
    if (tempSum > sumMax && LessCapacity(len,arr)) {
        sumMax = tempSum;
//        更新选择方法
        for (int i = 0; i < len; i++) {
            method[i] = visited[i];
        }
    }

}

// 背包问题的递归函数
void backpack(int w, int* arr, int* key, int len, int depth, int tempSum) {
    // 如果到达物品数组的末尾或背包容量已满,则遍历当前状态
    if (depth == len) {
        count++;
        Traverse(arr, len, tempSum, depth);
        return;
    }
    // 不选择当前物品
    visited[depth] = 0;
    backpack(w, arr, key, len, depth + 1, tempSum);

    // 如果能选择当前物品(背包容量足够)
    visited[depth] = 1; // 选择当前物品
    backpack(w - arr[depth], arr, key, len, depth + 1, tempSum + key[depth]); // 递归调用
}
// 判断重量<=15

int main() {
    // 重量
    int weight[] = { 2, 12, 1, 1, 4 };
    // 重量对应的价值
    int key[] = { 2, 4, 2, 1, 10 };

    backpack(capacity, weight, key, 5, 0, 0); // 调用背包问题的递归函数

    printf("----------------------------------分隔符----------------------------------\n");
    printf("总共有%d种情况\n",count);
    printf("重量: ");
    for (int i = 0; i < sizeof(weight)/sizeof (int); ++i) {
        printf("%d  ", weight[i]);
    }
    printf("\n");
    printf("选择: ");
    for (int i = 0; i < sizeof(weight)/sizeof (int); i++) {
        printf("%d  ", method[i]);
        if(method[i] == 1){
            weightSum+=weight[i];
        }
    }
    printf("\n 最终重量:%d",weightSum);
    printf("\n 最终最优金额:%d",sumMax);
    return 0;
}
posted @ 2024-05-25 19:05  Yang0710  阅读(89)  评论(0编辑  收藏  举报