分支限界法实现最优装载c++_分支限界法

6a63be7964f9ea6dd89ab3c6506d8c20.png

晓强Deep Learning的读书分享会,先从这里开始,从大学开始。大家好,我是晓强,计算机科学与技术专业研究生在读。我会不定时的更新我的文章,内容可能包括深度学习入门知识,具体包括CV,NLP方向的基础知识和学习的论文;网络表征学习的相关论文解读。当然我每天的读书心得也会分享给大家,可能涉及我们生活各个方面的书籍。我也会不定时回答大家的问题与大家一同进步,共同交流,互相监督,结交更多的朋友。希望大家多留言,多交流,多多关照。我在这里等你一同学习,如果需要相关资料也可以私信我,进入我们的群大家庭

【晓白】今天正值高考,给大家加油。还是要坚持下去的,努力终会有收获,只为了追求那个曾经的优秀的自己。所以今天中午抽时间写了一篇分支限界法的文章。希望大家点赞,关注,支持一下。谢谢精神合伙人的支持和鼓励。如果有准备秋招的同学,也可以来看一下,对大家很有帮助。有任何疑问可以私信,获得我们大家庭的联系方式,多多沟通,共同进步。如果高考结束以后大家对计算机学习有一定兴趣,或者家长朋友和考生希望以后报考计算机,学习计算机的,也可以关注我,看更多文章;详情私信,了解更多。可以咨询,辅导入门。今天更新第六章的前面先补充一下回溯法的效率。

第五章回溯法的效率分析:

一个回溯算法的效率在很大程度上依赖于以下几个因素:

(1)产生X[k]的时间

(2)满足显约束的x[k]值的个数

(3)计算约束函数Constraint的时间

(4)计算上界函数Bound的时间

(5)满足约束函数和上界函数约束的所有x[k]的个数,在选择约束函数时通常存在着生成结点数与约束函数计算量之间的折衷

重排原理:

163e5e7b5a38f6050ff1f9d55a3e00ce.png

30421d02f932bce103e750bf6224483f.png

解空间的结构一经选定,影响回溯法效率的前四个因素就可以确定,只剩下生成结点的数目是可变的,它将随问题的具体内容以及结点的不同生成方式而变动。

对于一个问题的具体实例,我们很难预测回溯法的算法行为。特别是我们很难估计出回溯法在解这一具体实例时所产生的结点数。这是我们在分析回溯法效率时遇到的主要困难。

蒙特卡罗方法:

估计回溯法将要产生的结点数目。主要思想是在解空间树上产生一条随机的路径,然后沿此路径来估算解空间树中满足约束条件的结点总数。

算法Estimate从解空间树的根结点开始选取一条随机路径,计算回溯法生成的结点总数m。

Estimate (int n, Type *x)

{ int m=1,r=1,k=1;

while (k<=n)

{

SetType T=x[k]的满足约束的可取值集合;

if (Size(T)==0)return m;

r*= Size(T); // Size(T)得到集合T大小

m+=r;

x[k]=Choose(T); //Choose(T) 从集合T随机地选一个元素

k++;

}

return m;

}

当用回溯法求解某一具体问题时,可用算法Estimate估算回溯法生成的结点数。

若要估算得更精确些,可选取若干条不同的随机路径(通常不超过20条),分别对各随机路径估计结点总数,然后再取这些结点总数的平均值,得到m的估算值。

例:8后问题

利用显约束排除那些有2个皇后在同一行或同一列的方法,也有8!种不同的方法。8后问题的解空间树的结点总数是:

02ddd1d7f25cc33f21a5d70064d1e957.png

ead4d9fd4e7e9830980be7740e89c37b.png

回溯法产生的结点数m是解空间树的结点总数的1.55%左右。说明回溯法的效率大大高于穷举法。

第六章 分支限界法

分支限界法类似于回溯法,也是一种在问题的解空间树T上搜索解的算法。但是,分支限界法与回溯法有不同的求解目标:回溯法的求解目标是找出T中满足约束条件的所有解,或任意一个解;分支限界法的求解目标则是找出T中使得某一目标函数值达到极小或极大的解,即问题在某种意义下的最优解。

由于求解目标不同, 导致分支限界法与回溯法在解空间树T上搜索的算法有两点不同:

(1)回溯法以深度优先的方式搜索解空间树T;分支限界法以广度优先或最小耗费优先的方式搜索解空间树T。

(2)回溯法一般只通过约束条件,而分支限界法不仅通过约束条件,而且通过目标函数的限界来减少无效搜索,提高求解效率。

分支限界法的搜索策略是:

在扩展结点处,先生成其所有儿子结点(使其变为活结点),然后再从当前的活结点表中选择下一个扩展结点。为了有效地选择下一个扩展结点,以加速搜索的进程,在每一活结点处,计算一个函数值(限界),并根据这些已计算出的函数值,从当前活结点表中选择一个最有利的结点作为扩展结点,使搜索朝着解空间树上有最优解的分支推进,以便尽快地找出一个最优解。这种方法就称为分支限界法。

一、分支限界法的基本思想

从活动结点表选择下一个扩展结点的原则体现在对活结点表的组织方式(即,数据结构)之中。常见的活结点表的组织方式有以下二种:

队列式(FIFO)

优先队列式(PQ, Prioroty Queue)---优先队列可用堆实现

所以,常见的分支限界法分为:

(1)队列式(FIFO)分支限界法

(2)优先队列式(PQ)分支限界法

用队列式分支限界法求解单源最短路径问题

f2e243063ed929cb394c64b23979f3ba.png

按队列式分支限界法求解单源最短路径的算法:

SSShortestPaths(v)

{ E.i=v;

E.length=0;

dist[v]=0; //源点V到源点V的最近距离

INSERT (Q, E); //Q是一个队列

while(!Empty(Q))

{ E=DELETE(Q);

if(dist[E.i]<E.length) continue; //源点V到顶点i的当前最近距离

for(j=1; j<=n; j++)

if ((c[E.i][j]<inf)&&(E.length+c[E.i][j]<dist[j]))

{ dist[j]=E.length+c[E.i][j];

prev[j]=E.i;

N.i=j;

N.length=dist[j];

INSERT(Q,N);

}

}

}

e05a50dc200ab9584922118fce34082c.png

48b0ebb2430ea7de5e1e0877ca476f74.png

d8a7a92f0bc140c21a0b56ce1ce02ee0.png

用优先队列式分支限界法求解单源最短路径问题

7fc7bc6bdcf05378af882d908ad246df.png

d8011f7e00fabf9b9b61e5d94dda02fd.png

aedf276c050b2a9d4824308c3f18c8b4.png

(1) 按队列式分支限界法求解多段图最短路径的算法:

ShortestPath(v)

{E.i=v; E.length=0;

Bound=inf; //也可用贪心法先确定一个初始界限

INSERT (Q, E); //Q是队列

while(!Empty(Q))

{ E=DELETE(Q);

if(Bound<E.length) continue;

for (j=1; j<=n; j++)

{ if ((c[E.i][j]<inf)&&(E.length+c[E.i][j]<Bound))

{ prev[j]=E.i;

if(j是终点)

{Bound=E.length+c[E.i][j];continue; }

N.i=j;

N.length= E.length+c[E.i][j];

INSERT(Q,N);

}

}

}

}

71cced8a78454568afa22cadcbb63fdd.png

按优先队列式分支限界法求解多段图问题的算法:

template <class Type>

void graph <Type> :: ShortestPath(int v)

{MinHeap <MinHeapNode <Type> > H(1000); //定义小根堆的容量为1000

MinHeapNode <Type> E;

E.i=v; E.length=0; //定义源为初始扩展结点

Bound=inf; //开始搜索问题的解空间

while(true)

{ if(E.length<Bound)

for(j=1; j<=n; j++)

if ((c[E.i][j]<inf)&&(E.length+c[E.i][j]<Bound))

{ prev[j]=E.i;

if(j是终点)

{Bound=E.length+c[E.i][j];continue; }

MinHeapNode <Type> N;

N.i=j; N.length= E.length+c[E.i][j];

H.Insert(N);

}

try { H.DeleteMin(E);} //从优先队列取下一个扩展结点

catch (OutOfBound) {break;} // 优先队列空

}

}

今天算法设计分析的第六章更新完毕,明天我会继续更新对于第五章,和第六章的补充知识,敬请期待。当然,后续我也打算给小伙伴们更新一下计算理论的介绍以便大家全面的学习。7.7-7.10是高考的日子,我也会继续更新,希望与大家一起坚持下去。祝顺利,金榜题名都圆大学梦。莘莘学子们,如果对计算机学习感兴趣也可以私信留言咨询,学习,推荐资料,一对一辅导交流都可以。加入大家庭,一起学习。感兴趣,关注我,阅读更多文章。连接如下,

晓强DL:第五章 回溯法(Backtrack)​zhuanlan.zhihu.com
52461dc901822eb3fe3694caf481d15a.png
晓强DL:图像处理必读论文之AlexNet​zhuanlan.zhihu.com
晓强DL:图像处理必读论文之二:VGG网络​zhuanlan.zhihu.com
52461dc901822eb3fe3694caf481d15a.png
晓强DL:第四章 贪心算法(Greedy Algorithms)​zhuanlan.zhihu.com
52461dc901822eb3fe3694caf481d15a.png
晓强DL:第三章 动态规划(Dynamic Programming )​zhuanlan.zhihu.com
52461dc901822eb3fe3694caf481d15a.png
晓强DL:第二章 递归与分治​zhuanlan.zhihu.com
52461dc901822eb3fe3694caf481d15a.png
晓强DL:计算机算法设计与分析第一章 算法概述​zhuanlan.zhihu.com
52461dc901822eb3fe3694caf481d15a.png
晓强DL:Opencv图像处理(一)​zhuanlan.zhihu.com
晓强DL:OpenCV图像处理(二)​zhuanlan.zhihu.com
晓强DL:Opencv图像处理(三)​zhuanlan.zhihu.com
晓强DL:Opencv图像处理 (四)​zhuanlan.zhihu.com
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,你的问题是关于分支限界法实现最优装载问题的C++代码。 首先,需要明确最优装载问题的定义:给定一些物品和一个容量为C的箱子,每个物品有各自的重量和价值,要求在不超过箱子容量的情况下,将价值最大化的物品装入箱子中。 接下来,我们可以使用分支限界法来解决这个问题。具体思路如下: 1. 将物品按照单位重量的价值从大到小排序。 2. 定义一个节点,包含当前所选物品的重量、价值、剩余容量和已选择的物品。 3. 对于每个节点,计算其可行的子节点。如果子节点的重量小于箱子容量,则将子节点加入队列中。 4. 对于每个可行的子节点,计算其上界(即该节点之后能够获得的最大价值),并更新最优解。 5. 选择上界最大的节点,将其扩展成子节点,重复步骤3-5,直到队列为空。 下面是实现最优装载问题的C++代码,其中使用了一个优先队列来存储节点,并按照上界从大到小排序: ```c++ #include <iostream> #include <queue> #include <vector> #include <algorithm> using namespace std; struct Node { int weight; // 已选物品的总重量 int value; // 已选物品的总价值 int capacity; // 剩余容量 vector<int> items; // 已选择的物品编号 double upper_bound; // 上界 bool operator<(const Node& other) const { return upper_bound < other.upper_bound; } }; double get_upper_bound(const Node& node, const vector<int>& weights, const vector<int>& values, int n) { double ub = node.value; int j = node.items.size(); int total_weight = node.weight; while (j < n && total_weight + weights[j] <= node.capacity) { ub += values[j]; total_weight += weights[j]; j++; } if (j < n) { ub += (node.capacity - total_weight) * (double)values[j] / weights[j]; } return ub; } int best_value(const vector<int>& weights, const vector<int>& values, int capacity) { int n = weights.size(); vector<int> indices(n); for (int i = 0; i < n; i++) { indices[i] = i; } sort(indices.begin(), indices.end(), [&](int a, int b) { return (double)values[a] / weights[a] > (double)values[b] / weights[b]; }); priority_queue<Node> q; Node root{ 0, 0, capacity, {}, get_upper_bound({ 0, 0, capacity, {}, 0 }, weights, values, n) }; q.push(root); int best = 0; while (!q.empty()) { Node node = q.top(); q.pop(); if (node.upper_bound < best) { break; } if (node.value > best) { best = node.value; } int i = node.items.empty() ? 0 : node.items.back() + 1; if (i < n) { Node left = node; left.weight += weights[indices[i]]; left.value += values[indices[i]]; left.capacity -= weights[indices[i]]; left.items.push_back(indices[i]); left.upper_bound = get_upper_bound(left, weights, values, n); if (left.upper_bound >= best) { q.push(left); } Node right = node; right.items.push_back(indices[i]); right.upper_bound = get_upper_bound(right, weights, values, n); if (right.upper_bound >= best) { q.push(right); } } } return best; } int main() { vector<int> weights = { 2, 3, 4, 5 }; vector<int> values = { 3, 4, 5, 6 }; int capacity = 8; cout << best_value(weights, values, capacity) << endl; // 输出13 return 0; } ``` 希望能够对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值