分支限界法解决0/1背包问题(C语言实现)

这篇具有很好参考价值的文章主要介绍了分支限界法解决0/1背包问题(C语言实现)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

分支限界法的基本思想

分支限界法的基本思想是,在分支结点上,预先分别估算沿着它的各个儿子结点向下搜索的路径中,目标函数可能取得的“界”,然后把这些儿子结点和它们可能所取得的“界”保存在一张结点表中,再根据题目要求选择表中“界”最大或最小的结点向下搜索。(一般用优先队列来处理这张结点表)这样当搜索到一个叶子结点时,如果该结点所估算的目标函数值就是结点表中的最大或者最小值,那么沿叶子结点到根结点的路径所确定的解就是问题的最优解,叶子结点的目标函数值就是问题的最大值或最小值。

参考:《算法分析与设计(第三版)》(郑宗汉、郑晓明编著)

解决背包问题的基本思路

首先要将物品按重量价值比排序。

同样还是一棵二叉树,沿左孩子则选,右孩子则不选。

初始化最大上界bound = 0。对于一个结点,计算其理想状态下可能获得的最大上界bound(理想状态也就是把物体看成可分割),将结点按bound递减顺序存入优先队列中;然后队头出队(也就是bound最大的结点),对于其左孩子和右孩子分别计算bound,重复上述步骤。如果到达叶子结点,且该叶子结点的bound比当前bound大,则更新bound值。如果队列内的一些结点的值小于bound,则无需沿着小于bound的值的结点继续搜索。(随着二叉树搜索深度增加,bound值越来越接近真实值),那么如果当前结点bound值都比另一条分支上的叶子结点bound值小,那继续搜索只会更小)

源程序代码

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<malloc.h>
#include<Windows.h>
#define N 100

int n;
int M;
typedef struct {
    float weight;
    float value;
    float x;// 价值重量比
    int num;//排序前的初始序号
    int flag;
}Goods[N];

typedef struct BiTNode {
    Goods g;
    float bound;//上界
    float w;//已选道路重量
    float v;
    int k;//搜索深度
}BiTNode;

BiTNode* qbase[N];
int choose[N];//物品选择情况
int rear = 0;
int front = 0;//队列指针

//初始化
void Init(Goods goods) {
    printf("输入物品数量和背包容量:");
    scanf("%d %d", &n, &M);
    for (int i = 0; i < n; i++) {
        printf("输入第%d个物品的重量和价值:", i + 1);
        scanf("%f %f", &goods[i].weight, &goods[i].value);
        goods[i].x = goods[i].value / goods[i].weight;
        goods[i].num = i;
        goods[i].flag = 0;
    }

}

//按物品价值重量比递减排序
void sort(Goods goods) {
    Goods temp;
    for (int i = 0; i < n - 1; i++) {
        for (int j = 0; j < n - 1 - i; j++) {
            if (goods[j].x < goods[j + 1].x) {
                temp[0] = goods[j + 1];
                goods[j + 1] = goods[j];
                goods[j] = temp[0];
            }
        }
    }
}

//入队
void Q_Insert(BiTNode* qbase[], BiTNode* xnode) {
    qbase[rear] = xnode;
    rear++;
}


//将最大值放在队首
BiTNode* Max_Q(BiTNode* qbase[]) {
    float max = 0;
    for (int i = front;i < rear;i++) {
        if (qbase[i]->bound > max) {
            max = qbase[i]->bound;
        }
    }
    for (int i = front;i < rear;i++) {
        if (qbase[i]->bound == max) {
            BiTNode* xnode = new BiTNode;
            xnode = qbase[i];
            qbase[i] = qbase[front];
            qbase[front] = xnode;
        }
    }
    return qbase[front];
}



//计算结点上界
void knap_bound(BiTNode* node, int M, int n) {
    float w = node->w;
    float v = node->v;
    int m = node->k;
    if (node->w > M) {
        //已选道路重量如果已经大于背包重量
        node->bound = 0;
    }
    else {
        while (m < n && node->w + node->g[m].weight <= M) {
            //按实际情况(不可分割)将背包容量尽可能达到最大值
            //也就是说加下一个物品超重,但不加则不超重
            w += node->g[m].weight;
            v += node->g[m].value;
            m++;
        }
        if (m < n) {
            //对物品进行分割
            //背包剩余容量*物品的价值重量比
            //就是该物品一部分(这一部分刚好满足背包装满)的价值
            node->bound = v + (M - w) * node->g[m].x;
        }
        else {
            node->bound = v;
        }
    }
}


//背包问题
float KnapSack(Goods goods) {
    BiTNode* xnode, * ynode, * znode;
    float bound = 0;
    xnode = new BiTNode;
    xnode->w = xnode->v = 0;
    xnode->k = 0;
    for (int i = 0;i < n;i++) {
        //将物品信息复制到结点中
        xnode->g[i] = goods[i];
    }

// ----------------初始化结束-----------------
    while (xnode->k < n) {
        ynode = new BiTNode;
        *ynode = *xnode;
        ynode->g[ynode->k].flag = 1;//选
        ynode->w += goods[ynode->k].weight;
        ynode->v += goods[ynode->k].value;
        ynode->k += 1;//搜索深度加一
        knap_bound(ynode, M, n);
        if (ynode->bound > bound) {
            Q_Insert(qbase, ynode);
            if (ynode->k == n) {
            //叶子结点则更新bound
                bound = ynode->bound;
            }
        }
        else {
            delete ynode;
        }
        znode = new BiTNode;
        *znode = *xnode;
        znode->g[znode->k].flag = 0;//不选
        znode->k += 1;
        knap_bound(znode, M, n);
        if (znode->bound > bound) {
            Q_Insert(qbase, znode);
            if (znode->k == n) {
                bound = znode->bound;
            }
        }
        else {
            delete znode;
        }
        delete xnode;//不要忘记释放结点空间
        xnode = Max_Q(qbase);//优先对列中bound最大的结点赋值给xnode
        front++;//队头出队,front++
    }
    
    float v = xnode->v;//输出最优解
    for (int i = 0;i < n;i++) {
        if (xnode->g[i].flag != 0) {
            //输出最优解向量
            choose[xnode->g[i].num] = 1;//num是未排序前的原始序号
        }
    }
    delete xnode;
    return v;
}

int main() {
    Goods goods;
    Init(goods);
    sort(goods);
    printf("选择物品情况:");
    float value = KnapSack(goods);
    for (int i = 0;i < n;i++) {
        printf("%d ", choose[i]);
    }
    printf("\n最大价值:");
    printf("%.1f", value);
    system("pause");
    return 0;
}

运行结果

分支限界法解决0/1背包问题(C语言实现)

 ps:由于笔者水平有限,并且也是刚刚学习分支限界法,花了很长的时间写+调试,若有错误,敬请指正。文章来源地址https://www.toymoban.com/news/detail-510984.html

到了这里,关于分支限界法解决0/1背包问题(C语言实现)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 01背包(动态规划,贪心算法,回溯法,分支限界法)

    有n个物品,它们有各自的体积和价值,现有给定容量的背包,如何让背包里装入的物品具有最大的价值总和? number=4,capacity=8 物品编号(i) W(体积) V(价值) 1 2 3 2 3 4 3 4 5 4 5 6 1.什么是动态规划 1.动态规划算法是通过拆分问题,定义问题状态和状态之间的关系, 使得

    2024年02月08日
    浏览(68)
  • 分支限界TSP(旅行商问题)

    【问题】 TSP 问题(traveling salesman problem) 是指旅行家要旅行 n 个城市, 要求各个城市经历且仅经历一次然后回到出发城市, 并要求所走的路程最短。 【想法】 首先确定目标函数的界[down, up], 可以采用贪心法确定 TSP 问题的一个上界。 如何求得 TSP 问题的一个合理的下界呢

    2024年02月08日
    浏览(47)
  • N皇后问题(分支限界法)

    在 n * n 格的棋盘上放置彼此不受攻击的 n 个皇后。按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。 n 皇后问题等价于在 n * n 的棋盘上放置 n 个皇后,任何 2个皇后不放在同一行或同一列或同一斜线上。 设计一个解 n 皇后问题的队列式分支

    2024年02月04日
    浏览(35)
  • 最小长度电路板排列问题(分支限界法)

    分支限界法求最佳排列。 具体细节见注释。

    2024年02月03日
    浏览(48)
  • 动态规划算法解决背包问题,算法分析与C语言代码实现,时间效率解析

    🎊【数据结构与算法】专题正在持续更新中,各种数据结构的创建原理与运用✨,经典算法的解析✨都在这儿,欢迎大家前往订阅本专题,获取更多详细信息哦🎏🎏🎏 🪔本系列专栏 -  数据结构与算法_勾栏听曲_0 🍻欢迎大家  🏹  点赞👍  评论📨  收藏⭐️ 📌个人主

    2023年04月16日
    浏览(50)
  • 最大团问题(MPP)之回溯法、分支限界法

    给定一个无向图 G = ( V , E ) G=(V, E) G = ( V , E ) , 其中 V V V 是图的顶点集, E E E 是图的边集: 完全子图:如果 U ⊆ V U⊆V U ⊆ V ,对任意的 u , v ∈ U u, v∈U u , v ∈ U , 有 ( u , v ) ∈ E (u, v)∈E ( u , v ) ∈ E , 则称 U U U 是 V V V 的完全子图 团: G G G 的完全子图 U U U 就是 G G G 的团。

    2024年02月07日
    浏览(41)
  • 单源最短路径问题——分支限界法(Java)

    1.1 分支限界法求解目标 分支限界法与回溯法的不同求解目标: 回溯法的求解目标:找出解空间树中满足约束条件的 所有解 ; 分支限界法的求解目标:找出满足约束条件的 一个解 ,或是在满足约束条件的解中找出使用某一目标函数值达到极大或极小的解,即在某种意义下

    2024年02月06日
    浏览(37)
  • java实现0-1背包问题方案(动态规划-贪心算法-回溯-分支定界)

    动态规划算法时间复杂度较低,能够求解较大规模的问题,但空间复杂度较高,不适用于数据量较大的问题。 贪心算法时间复杂度较低,能够求解较大规模的问题,但不能保证求得的解是最优解。 回溯算法能够求解较小规模的问题,但时间复杂度较高,不适用于数据量较大

    2024年02月01日
    浏览(130)
  • 贪心算法解决背包问题和动态规划解决0-1背包问题(c语言)

    运行结果如下: 运行结果如下: 总结: 贪心算法: 每一步都做出当时看起来最佳的选择,也就是说,它总是做出局部最优的选择。 贪心算法的设计步骤: 对其作出一个选择后,只剩下一个子问题需要求解。 证明做出贪心选择后,原问题总是存在最优解,即贪心选择总是安

    2024年02月04日
    浏览(56)
  • C语言动态规划解决0-1背包问题

    动态规划(Dynamic Programming,简称DP)是一种在数学、计算机科学和经济学中使用的,通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。动态规划常常适用于有重叠子问题和最优子结构性质的问题,它能够将问题分解为相互独立的子问题,并将子问题的解存储

    2024年04月28日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包