分支限界法C++ 学习&练习

Posted 图灵奖未来得主

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了分支限界法C++ 学习&练习相关的知识,希望对你有一定的参考价值。

分支界限法

许多问题的解决实际上是多步决策问题,每走一步有都有多步动作可以选择,逐步形成一个状态空间搜索树。可以通过约束函数和限界函数可以把分支去掉。
剪枝:用限界函数/约束函数避免无效搜索。
约束函数:不能满足约束的子树不再搜索
限界函数:不能得到最优价值的子树不再搜索
(当我们知道从当前的状态探索下去,不可能优于当前已知的最优价值,就没有必要探索下去了)
已背包问题为例:最大值
·当前已有可行解的最大价值,记为B。
·当前(状态)结点N子树的最大价值bound(N)。
if bound(N)<B 不需要再探索结点N了
背包问题中:
bound(N)=当前已经装入价值+剩下的能装最大价值
即 cv+remaining_value<bestV(已知的最优值)

深度优先搜索-分支限界

//模板一:
dfs(c) ://c是当前状态
	if reject(c) : return;//reject以上两种情况
	if accept(c) :output, return;
	for (c的每个可达状态s)
		dfs(s);
//模板二:
dfs(c) ://c是当前状态
	if accept(c) : output();
	for c的每个可达状态s:
		push(s);
		if not reject(s):
			dfs(s)
		pop()//用来保存路径

广度优先搜索-分支限界

bfs():
	初始化B为无穷大(或无穷小)
	启发式搜索(如贪婪)得到可行解更新B
	初始化状态队列
	while 队列不空
		出队一个结点N
		if N 表示一个可行解x //如达到叶子结点
			if f(x)优于B:则B=f(x)
		else
				for 每个分支N
					ifbound(N)优于B)
						N入队

练习

0/1背包问题

分析:按照单位重量价值排序,分别判断“好”的物品要不要选
bound©=cv+(W-cw)*(Vi+1)/(Wi+1)
当前结点为xi,那么下面可以选择的剩下的最好的单位重量(Vi+1)/(Wi+1)装满(但实际上不一定正好,只能说这样求出来的是最好的),如果最好的都比当前的最小重量小,那直接别看了(这是当前结点最大价值的上界)
具体来看每一步:
给定:w=(4,7,5,3),v=(40,42,25,12),W=10
1.cw=0,cv=0,ub=100
2.x1=1,cw=4,cv=40,ub=76 B=40
3.x1=1 x2=1 不满足约束条件
4.x1=1 x2=0 cw=4 cv=40 ub=70 B=40
5.x1=1 x2=0 x3=1 cw=9 cv=65 ub=69 B=65
6.x1=1 x2=0 x3=1 x4=1 不满足约束条件
然后再回溯找有没有更小的啦~
最后找到最好的是65

伪代码:
对items按v/w排序
B=0
初始化状态队列,初始状态进队列
while队列不空
	出队一个结点N
	if N表示可行解:continue;
	for 每个分支Ni
		if Ni是可行解且cv(Ni)优于B:则B=cv(Ni);//f(x)
		if bound(Ni)优于B:
			Ni入队

例题:1. 利用分支限界法求 0-1 背包问题。有 n = 20 个物品,背包最大可装载 M = 878 Kg。物品重量和价值分别如下:
W=92,4,43,83,84,68,92,82,6,44,32,18,56,83,25,96,70,48,14,58,
V=44,46,90,72,91,40,75,35,8,54,78,40,77,15,61,17,75,29,75,63,
求最优背包价值。
这里适用深度优先遍历写的代码

#include<iostream>
#include<algorithm>
using namespace std;
static int B = 0;//初始化最优值
static int M = 878, n = 20;
typedef struct item 
	int w, v;
	double good;
;
bool cmp(item a, item b) 
	return a.good >= b.good;

void create(item  items[], int x[], int y[]) 
	for (int i = 0; i < 20; i++) 
		items[i].w = x[i];
		items[i].v = y[i];
		items[i].good = (y[i] * 1.0) / x[i];
	
	sort(items, items + 20, cmp);


void dfs(item items[],int i,int cv,int cw) 
	if (i >= 20) return;
	cv += items[i].v;
	cw += items[i].w;
	if (cw <= M && (cv + items[i + 1].good * (M - cw)) >= B) 
		if (cv > B) 
			B = cv;
		
		dfs(items, i + 1,cv,cw);
		cv -= items[i].v;
		cw -= items[i].w;
		dfs(items, i + 1, cv, cw);
	
	else 
		cv -= items[i].v;
		cw -= items[i].w;
		dfs(items, i + 1, cv, cw);
	


int main() 
	item  items[20];
	int x[20] =  92,4,43,83,84,68,92,82,6,44,32,18,56,83,25,96,70,48,14,58 ;
	int y[20] =  44,46,90,72,91,40,75,35,8,54,78,40,77,15,61,17,75,29,75,63 ;
	create(items, x, y);//创建排序好的items
	int  cv = 0, cw = 0;
	dfs(items,0, cv, cw);
	cout << B;


以上是关于分支限界法C++ 学习&练习的主要内容,如果未能解决你的问题,请参考以下文章

分支限界法C++ 学习&练习

分支限界法C++ 学习&练习

算法与程序设计:分支限界法

TSP问题(旅行商问题)[分支限界法]

布线问题(分支限界法)

分支限界法