0034算法笔记——【分支限界法】最优装载问题

0034算法笔记——【分支限界法】最优装载问题
0034算法笔记——【分支限界法】最优装载问题

问题描述

有一批共个集装箱要装上2艘载重量分别为C1和C2的轮船,其中

集装箱i的重量为Wi,且装载问题要求确定是否有一个合理的装载方案可将这个集装箱装上这2艘轮船。如果有,找出一种装载方案。

容易证明:如果一个给定装载问题有解,则采用下面的策略可得到最优装载方案。

(1)首先将第一艘轮船尽可能装满;

(2)将剩余的集装箱装上第二艘轮船。

1、队列式分支限界法求解

在算法的循环体中,首先检测当前扩展结点的左儿子结点是否为可行结点。如果是则将其加入到活结点队列中。然后将其右儿子结点加入到活结点队列中(右儿子结点一定是可行结点)。2个儿子结点都产生后,当前扩展结点被舍弃。

活结点队列中的队首元素被取出作为当前扩展结点,由于队列中每一层结点之后都有一个尾部标记-1,故在取队首元素时,活结点队列一定不空。当取出的元素是-1时,再判断当前队列是否为空。如果队列非空,则将尾部标记-1加入活结点队列,算法开始处理下一层的活结点。

节点的左子树表示将此集装箱装上船,右子树表示不将此集装箱装上船。设bestw是当前最优解;ew是当前扩展结点所相应的重量;r 是剩余集装箱的重量。则当ew+r

为了在算法结束后能方便地构造出与最优值相应的最优解,算法必须存储相应子集树中从活结点到根结点的路径。为此目的,可在每个结点处设置指向其父结点的指针,并设置左、右儿子标志。

找到最优值后,可以根据parent回溯到根节点,找到最优解。

算法具体代码实现如下:

1、Queue.h

[cpp]view plain copy

1.#include

https://www.360docs.net/doc/bf5972516.html,ing namespace std;

3.

4.template

5.class Queue

6.{

7.public:

8. Queue(int MaxQueueSize=50);

9. ~Queue(){delete [] queue;}

10.bool IsEmpty()const{return front==rear;}

11.bool IsFull(){return ( ( (rear+1) %MaxSize==front )?1:0);}

12. T Top() const;

13. T Last() const;

14. Queue& Add(const T& x);

15. Queue& AddLeft(const T& x);

16. Queue& Delete(T &x);

17.void Output(ostream& out)const;

18.int Length(){return (rear-front);}

19.private:

20.int front;

21.int rear;

22.int MaxSize;

23. T *queue;

24.};

25.

26.template

27.Queue::Queue(int MaxQueueSize)

28.{

29. MaxSize=MaxQueueSize+1;

30. queue=new T[MaxSize];

31. front=rear=0;

32.}

33.

34.template

35.T Queue::Top()const

36.{

37.if(IsEmpty())

38. {

39. cout<<"queue:no element,no!"<

40.return 0;

41. }

42.else return queue[(front+1) % MaxSize];

43.}

44.

45.template

46.T Queue ::Last()const

47.{

48.if(IsEmpty())

49. {

50. cout<<"queue:no element"<

51.return 0;

52. }

53.else return queue[rear];

54.}

55.

56.template

57.Queue& Queue::Add(const T& x)

58.{

59.if(IsFull())cout<<"queue:no memory"<

60.else

61. {

62. rear=(rear+1)% MaxSize;

63. queue[rear]=x;

64. }

65.return *this;

66.}

67.

68.template

69.Queue& Queue::AddLeft(const T& x)

70.{

71.if(IsFull())cout<<"queue:no memory"<

72.else

73. {

74. front=(front+MaxSize-1)% MaxSize;

75. queue[(front+1)% MaxSize]=x;

76. }

77.return *this;

78.}

79.

80.template

81.Queue& Queue ::Delete(T & x)

82.{

83.if(IsEmpty())cout<<"queue:no element(delete)"<

84.else

85. {

86. front=(front+1) % MaxSize;

87. x=queue[front];

88. }

89.return *this;

90.}

91.

92.

93.template

94.void Queue ::Output(ostream& out)const

95.{

96.for(int i=rear%MaxSize;i>=(front+1)%MaxSize;i--)

97. out<

98.}

99.

100.template

101.ostream& operator << (ostream& out,const Queue& x) 102.{x.Output(out);return out;}

2、6d3-1.cpp

[cpp]view plain copy

1.//装载问题队列式分支限界法求解

2.#include "stdafx.h"

3.#include "Queue.h"

4.#include

https://www.360docs.net/doc/bf5972516.html,ing namespace std;

6.

7.const int N = 4;

8.

9.template

10.class QNode

11.{

12.template

13.friend void EnQueue(Queue*>&Q,Type wt,int i,int n,Type bestw

,QNode*E,QNode *&bestE,int bestx[],bool ch);

14.

15.template

16.friend Type MaxLoading(Type w[],Type c,int n,int bestx[]);

17.

18.private:

19. QNode *parent; //指向父节点的指针

20.bool LChild; //左儿子标识

21. Type weight; //节点所相应的载重量

22.};

23.

24.template

25.void EnQueue(Queue*>&Q,Type wt,int i,int n,Type bestw,QNode

>*E,QNode *&bestE,int bestx[],bool ch);

26.

27.template

28.Type MaxLoading(Type w[],Type c,int n,int bestx[]);

29.

30.int main()

31.{

32.float c = 70;

33.float w[] = {0,20,10,26,15};//下标从1开始

34.int x[N+1];

35.float bestw;

36.

37. cout<<"轮船载重为:"<

38. cout<<"待装物品的重量分别为:"<

39.for(int i=1; i<=N; i++)

40. {

41. cout<

42. }

43. cout<

44. bestw = MaxLoading(w,c,N,x);

45.

46. cout<<"分支限界选择结果为:"<

47.for(int i=1; i<=4; i++)

48. {

49. cout<

50. }

51. cout<

52. cout<<"最优装载重量为:"<

53.

54.return 0;

55.}

56.

57.//将活节点加入到活节点队列Q中

58.template

59.void EnQueue(Queue*>&Q,Type wt,int i,int n,Type bestw,QNode

>*E,QNode *&bestE,int bestx[],bool ch)

60.{

61.if(i == n)//可行叶节点

62. {

63.if(wt == bestw)

64. {

65.//当前最优装载重量

66. bestE = E;

67. bestx[n] = ch;

68. }

69.return;

70. }

71.//非叶节点

72. QNode *b;

73. b = new QNode;

74. b->weight = wt;

75. b->parent = E;

76. b->LChild = ch;

77. Q.Add(b);

78.}

79.

80.template

81.Type MaxLoading(Type w[],Type c,int n,int bestx[])

82.{//队列式分支限界法,返回最优装载重量,bestx返回最优解

83.//初始化

84. Queue*> Q; //活节点队列

85. Q.Add(0); //同层节点尾部标识

86.int i = 1; //当前扩展节点所处的层

87. Type Ew = 0, //扩展节点所相应的载重量

88. bestw = 0, //当前最优装载重量

89. r = 0; //剩余集装箱重量

90.

91.for(int j=2; j<=n; j++)

92. {

93. r += w[j];

94. }

95.

96. QNode *E = 0, //当前扩展节点

97. *bestE; //当前最优扩展节点

98.

99.//搜索子集空间树

100.while(true)

101. {

102.//检查左儿子节点

103. Type wt = Ew + w[i];

104.if(wt <= c)//可行节点

105. {

106.if(wt>bestw)

107. {

108. bestw = wt;

109. }

110. EnQueue(Q,wt,i,n,bestw,E,bestE,bestx,true); 111. }

112.

113.//检查右儿子节点

114.if(Ew+r>bestw)

115. {

116. EnQueue(Q,Ew,i,n,bestw,E,bestE,bestx,false); 117. }

118. Q.Delete(E);//取下一扩展节点

119.

120.if(!E)//同层节点尾部

121. {

122.if(Q.IsEmpty())

123. {

124.break;

125. }

126. Q.Add(0); //同层节点尾部标识

127. Q.Delete(E); //取下一扩展节点

128. i++; //进入下一层

129. r-=w[i]; //剩余集装箱重量

130. }

131. Ew =E->weight; //新扩展节点所对应的载重量

132. }

133.

134.//构造当前最优解

135.for(int j=n-1; j>0; j--)

136. {

137. bestx[j] = bestE->LChild;

138. bestE = bestE->parent;

139. }

140.return bestw;

141.}

程序运行结果如图:

2、优先队列式分支限界法求解

解装载问题的优先队列式分支限界法用最大优先队列存储活结点表。活结点x在优先队列中的优先级定义为从根结点到结点x的路径所相应的载重量再加上剩余集装箱的重量之和。

优先队列中优先级最大的活结点成为下一个扩展结点。以结点x为根的子树中所有结点相应的路径的载重量不超过它的优先级。子集树中叶结点所相应的载重量与其优先级相同。

在优先队列式分支限界法中,一旦有一个叶结点成为当前扩展结点,则可以断言该叶结点所相应的解即为最优解。此时可终止算法。

算法具体代码实现如下:

1、MaxHeap.h

[cpp]view plain copy

1.template

2.class MaxHeap

3.{

4.public:

5. MaxHeap(int MaxHeapSize = 10);

6. ~MaxHeap() {delete [] heap;}

7.int Size() const {return CurrentSize;}

8.

9. T Max()

10. { //查

11.if (CurrentSize == 0)

12. {

13.throw OutOfBounds();

14. }

15.return heap[1];

16. }

17.

18. MaxHeap& Insert(const T& x); //增

19. MaxHeap& DeleteMax(T& x); //删

20.

21.void Initialize(T a[], int size, int ArraySize);

22.

23.private:

24.int CurrentSize, MaxSize;

25. T *heap; // element array

26.};

27.

28.template

29.MaxHeap::MaxHeap(int MaxHeapSize)

30.{// Max heap constructor.

31. MaxSize = MaxHeapSize;

32. heap = new T[MaxSize+1];

33. CurrentSize = 0;

34.}

35.

36.template

37.MaxHeap& MaxHeap::Insert(const T& x)

38.{// Insert x into the max heap.

39.if (CurrentSize == MaxSize)

40. {

41. cout<<"no space!"<

42.return *this;

43. }

44.

45.// 寻找新元素x的位置

46.// i——初始为新叶节点的位置,逐层向上,寻找最终位置

47.int i = ++CurrentSize;

48.while (i != 1 && x > heap[i/2])

49. {

50.// i不是根节点,且其值大于父节点的值,需要继续调整

51. heap[i] = heap[i/2]; // 父节点下降

52. i /= 2; // 继续向上,搜寻正确位置

53. }

54.

55. heap[i] = x;

56.return *this;

57.}

58.

59.template

60.MaxHeap& MaxHeap::DeleteMax(T& x)

61.{// Set x to max element and delete max element from heap.

62.// check if heap is empty

63.if (CurrentSize == 0)

64. {

65. cout<<"Empty heap!"<

66.return *this;

67. }

68.

69. x = heap[1]; // 删除最大元素

70.// 重整堆

71. T y = heap[CurrentSize--]; // 取最后一个节点,从根开始重整

72.

73.// find place for y starting at root

74.int i = 1, // current node of heap

75. ci = 2; // child of i

76.

77.while (ci <= CurrentSize)

78. {

79.// 使ci指向i的两个孩子中较大者

80.if (ci < CurrentSize && heap[ci] < heap[ci+1])

81. {

82. ci++;

83. }

84.// y的值大于等于孩子节点吗?

85.if (y >= heap[ci])

86. {

87.break; // 是,i就是y的正确位置,退出

88. }

89.

90.// 否,需要继续向下,重整堆

91. heap[i] = heap[ci]; // 大于父节点的孩子节点上升

92. i = ci; // 向下一层,继续搜索正确位置

93. ci *= 2;

94. }

95.

96. heap[i] = y;

97.return *this;

98.}

99.

100.template

101.void MaxHeap::Initialize(T a[], int size,int ArraySize) 102.{// Initialize max heap to array a.

103.delete [] heap;

104. heap = a;

105. CurrentSize = size;

106. MaxSize = ArraySize;

107.

108.// 从最后一个内部节点开始,一直到根,对每个子树进行堆重整109.for (int i = CurrentSize/2; i >= 1; i--)

110. {

111. T y = heap[i]; // 子树根节点元素

112.// find place to put y

113.int c = 2*i; // parent of c is target

114.// location for y

115.while (c <= CurrentSize)

116. {

117.// heap[c] should be larger sibling

118.if (c < CurrentSize && heap[c] < heap[c+1]) 119. {

120. c++;

121. }

122.// can we put y in heap[c/2]?

123.if (y >= heap[c])

124. {

125.break; // yes

126. }

127.

128.// no

129. heap[c/2] = heap[c]; // move child up

130. c *= 2; // move down a level

131. }

132. heap[c/2] = y;

133. }

134.}

2、6d3-2.cpp

[cpp]view plain copy

1.//装载问题优先队列式分支限界法求解

2.#include "stdafx.h"

3.#include "MaxHeap.h"

4.#include

https://www.360docs.net/doc/bf5972516.html,ing namespace std;

6.

7.const int N = 4;

8.

9.class bbnode;

10.

11.template

12.class HeapNode

13.{

14.template

15.friend void AddLiveNode(MaxHeap>& H,bbnode *E,Type wt,boo

l ch,int lev);

16.template

17.friend Type MaxLoading(Type w[],Type c,int n,int bestx[]);

18.public:

19. operator Type() const{return uweight;}

20.private:

21. bbnode *ptr; //指向活节点在子集树中相应节点的指针

22. Type uweight; //活节点优先级(上界)

23.int level; //活节点在子集树中所处的层序号

24.};

25.

26.class bbnode

27.{

28.template

29.friend void AddLiveNode(MaxHeap>& H,bbnode *E,Type wt,boo

l ch,int lev);

30.template

31.friend Type MaxLoading(Type w[],Type c,int n,int bestx[]);

32.friend class AdjacencyGraph;

33.

34.private:

35. bbnode *parent; //指向父节点的指针

36.bool LChild; //左儿子节点标识

37.};

38.

39.template

40.void AddLiveNode(MaxHeap>& H,bbnode *E,Type wt,bool ch,int le

v);

41.

42.template

43.Type MaxLoading(Type w[],Type c,int n,int bestx[]);

44.

45.

46.int main()

47.{

48.float c = 70;

49.float w[] = {0,20,10,26,15};//下标从1开始

50.int x[N+1];

51.float bestw;

52.

53. cout<<"轮船载重为:"<

54. cout<<"待装物品的重量分别为:"<

55.for(int i=1; i<=N; i++)

56. {

57. cout<

58. }

59. cout<

60. bestw = MaxLoading(w,c,N,x);

61.

62. cout<<"分支限界选择结果为:"<

63.for(int i=1; i<=4; i++)

64. {

65. cout<

66. }

67. cout<

68. cout<<"最优装载重量为:"<

69.

70.return 0;

71.}

72.

73.//将活节点加入到表示活节点优先队列的最大堆H中

74.template

75.void AddLiveNode(MaxHeap>& H,bbnode *E,Type wt,bool ch,int le

v)

76.{

77. bbnode *b = new bbnode;

78. b->parent = E;

79. b->LChild = ch;

80. HeapNode N;

81.

82. N.uweight = wt;

83. N.level = lev;

84. N.ptr = b;

85. H.Insert(N);

86.}

87.

88.//优先队列式分支限界法,返回最优载重量,bestx返回最优解

89.template

90.Type MaxLoading(Type w[],Type c,int n,int bestx[])

91.{

92.//定义最大的容量为1000

93. MaxHeap> H(1000);

94.

95.//定义剩余容量数组

96. Type *r = new Type[n+1];

97. r[n] = 0;

98.

99.for(int j=n-1; j>0; j--)

100. {

101. r[j] = r[j+1] + w[j+1];

102. }

103.

104.//初始化

105.int i = 1;//当前扩展节点所处的层

106. bbnode *E = 0;//当前扩展节点

107. Type Ew = 0; //扩展节点所相应的载重量

108.

109.//搜索子集空间树

110.while(i!=n+1)//非叶子节点

111. {

112.//检查当前扩展节点的儿子节点

113.if(Ew+w[i]<=c)

114. {

115. AddLiveNode(H,E,Ew+w[i]+r[i],true,i+1); 116. }

117.//右儿子节点

118. AddLiveNode(H,E,Ew+r[i],false,i+1);

119.

120.//取下一扩展节点

121. HeapNode N;

122. H.DeleteMax(N);//非空123. i = N.level;

124. E = N.ptr;

125. Ew = N.uweight - r[i-1]; 126. }

127.

128.//构造当前最优解

129.for(int j=n; j>0; j--) 130. {

131. bestx[j] = E->LChild; 132. E = E->parent;

133. }

134.

135.return Ew;

136.}

程序运行结果如图:

(完整版)分支限界算法作业分配问题

分支限界法的研究与应用 摘要: 分支限界法与回溯法的不同:首先,回溯法的求解目标是找出解空间树中满足约束条件的所有解,而分支限界法的求解目标则是找出满足约束条件的一个解,或是在满足约束条件的解中找出在某种意义下的最优解。其次,回溯法以深度优先的方式搜索解空间树,而分支限界法则一般以广度优先或以最小耗费优先的方式搜索解空间树。再者,回溯法空间效率高;分支限界法往往更“快”。 分支限界法常以广度优先或以最小耗费(最大效益)优先的方式搜索问题的解空间树。在分支限界法中,每一个活结点只有一次机会成为扩展结点。活结点一旦成为扩展结点,就一次性产生其所有儿子结点。在这些儿子结点中,导致不可行解或导致非最优解的儿子结点被舍弃,其余儿子结点被加入活结点表中。此后,从活结点表中取下一结点成为当前扩展结点,并重复上述结点扩展过程。这个过程一直持续到找到所需的解或活结点表为空时为止。 常见的分支限界法有:队列式分支限界法,按照队列先进先出原则选取下一个结点为扩展结点。栈式分支限界法,按照栈后进先出原则选取下一个结点为扩展结点。优先队列式分支限界法,按照规定的结点费用最小原则选取下一个结点为扩展结点(最采用优先队列实现)。 分支搜索法是一种在问题解空间上进行搜索尝试的算法。所谓分支是采用广度优先的策略国,依次搜索E-结点的所有分支,也就是所有的相邻结点。和回溯法一样,在生成的结点中,抛弃那些不满足约束条件的结点,其余结点加入活结点表。然后从表中选择一个结点作为下一个E-结点,断续搜索。 关键词: 分支限界法回溯法广度优先分支搜索法

目录 第1章绪论 (3) 1.1 分支限界法的背景知识 (3) 1.2 分支限界法的前景意义 (3) 第2章分支限界法的理论知识.................. 错误!未定义书签。 2.1 问题的解空间树 ............................................... 错误!未定义书签。 2.2 分支限界法的一般性描述 (6) 第3章作业分配问题 (7) 3.1 问题描述 (7) 3.2 问题分析 (7) 3.3 算法设计 (8) 3.4 算法实现 (10) 3.5 测试结果与分析 (12) 第4章结论 (13) 参考文献 (14)

贪心算法解决最优装载问题

算法设计与分析实验报告 //author : Kevin Black //这个是我刚刚做好的作业,我觉得应该上传一些文档到豆丁 //老师···假如你看到我的作业跟网上的这个文章一样···你别以为我是抄的啊··· //记得看看作者的名字啊!! 贪心算法之最优装载问题 一. 实验目的 掌握贪心算法的基本思想(具体阐述) 掌握贪心算法的基本要素:贪心选择性质和最优子结构性质 二. 实验内容 贪心算法基本思想: 整体划分成部分,分而治之。每个部分中寻找最优解,然后综合所有部分最优解。这是,可能得到整体的最优解,但往往得到的是近似的最优解。 贪心算法基本要素: 1. 贪心选择性质 所谓贪心选择性质是指所求问题的整体最优解可以通过一系列局部最优的选择,即贪心选择来达到。这是贪心算法可行的第一个基本要素,也是贪心算法与动态规划算法的主要区别。 2. 最优子结构性质 当一个问题的最优解包含其子问题的最优解时,称此问题具有最优子结构性质。 最优装载问题 1. 问题描述: 有一批集装箱要装上一艘载重量为c的轮船。其中集装箱i的重量为Wi。最优装载问题要求确定在装载体积不受限制的情况下,将尽可能多的集装箱装上轮船。 2. 数学描述:

三. 实验程序及运行结果 #include #include void Swap(int &x,int &y)//交换 { int t; t=x; x=y; y=t; } void sort(int w[],int t[],int n)//排序,由小到大 { for(int m=0;m0) { lastExchangeIndex=0; for(j=0;j

回溯法与分支限界法的分析与比较

回溯法与分支限界法的分析与比较 摘要:通过对回溯法与分支限界法的简要介绍,进一步分析和比较这两种算法在求解问题时的差异,并通过具体的应用来说明两种算法的应用场景及侧重点。 关键词:回溯法分支限界法n后问题布线问题 1、引言 1.1回溯法 回溯法在问题的解空间树中,按深度优先策略,从根结点出发搜索解空间树。算法搜索至解空间树的任意一点时,先判断该结点是否包含问题的解。如果肯定不包含,则跳过对该结点为根的子树的搜索,逐层向其祖先结点回溯;否则,进入该子树,继续按深度优先策略搜索。这种以深度优先方式系统搜索问题解的算法称为回溯法。 1.2分支限界法 分支限界法是以广度优先或以最小耗费优先的方式搜索解空间树,在每一个活结点处,计算一个函数值,并根据函数值,从当前活结点表中选择一个最有利的结点作为扩展结点,使搜索朝着解空间上有最优解的分支推进,以便尽快地找出一个最优解,这种方法称为分支限界法。 2、回溯法的基本思想 用回溯法解问题时,应明确定义问题的解空间。问题的解空间至少应包含问题的一个解。之后还应将解空间很好的组织起来,使得能用回溯法方便的搜索整个解空间。在组织解空间时常用到两种典型的解空间树,即子集树和排列树。确定了解空间的组织结构后,回溯法从开始结点出发,以深度优先方式搜索整个解空间。这个开始结点成为活结点,同时也成为当前的扩展结点。在当前的扩展结点处,搜索向纵深方向移至一个新结点。这个新结点就成为新的活结点,并成为当前扩展结点。如果在当前的扩展结点处不能再向纵深方向移动,则当前扩展结点就成为死结点。此时,应往回移动至最近的一个活结点处,并使这个活结点成为当前的扩展结点。回溯法以这种工作方式递归的在解空间中搜索,直至找到所要求的解或解空间中已无活结点时为止。 3、分支限界法的基本思想 用分支限界法解问题时,同样也应明确定义问题的解空间。之后还应将解空间很好的组织起来。分支限界法也有两种组织解空间的方法,即队列式分支限界法和优先队列式分支限界法。两者的区别在于:队列式分支限界法按照队列先进先出的原则选取下一个节点为扩展节点,而优先队列式分支限界法按照优先队列

算法设计实验_贪心算法背包问题

《算法分析与设计》 课程实验 专业年级:信息与计算科学 学生学号: 学生姓名: 实验题目:用贪婪法求解背包问题 指导老师: 实验时间:20xx年xx月x日 一、实验内容 用贪婪法求解背包问题 要求:用非递归实现 二、实验步骤 2.1、理解算法思想和问题要求; 2.2、写出每个操作的算法 非递归算法: greedbag() { int N; int c;

int[] w; int[] v; Scanner scan=new Scanner(System.in); System.out.print("输入背包的容量:"); c=scan.nextInt(); System.out.print("输入物品的数量:"); N=scan.nextInt(); System.out.print("分别输入物品的价值:"); v=new int[N]; for(int i=0;i

算法分析与设计》期末考试复习题纲(完整版)

《算法分析与设计》期末复习题 一、选择题 1.算法必须具备输入、输出和( D )等4个特性。 A.可行性和安全性B.确定性和易读性 C.有穷性和安全性D.有穷性和确定性 2.算法分析中,记号O表示( B ),记号Ω表示( A ) A.渐进下界 B.渐进上界 C.非紧上界 D.紧渐进界 3.假设某算法在输入规模为n时的计算时间为T(n)=3*2^n。在某台计算机上实现并完 成概算法的时间为t秒。现有另一台计算机,其运行速度为第一台的64倍,那么在这台新机器上用同一算法在t秒内能解输入规模为多大的问题( B )解题方法:3*2^n*64=3*2^x A.n+8 B.n+6 C.n+7 D.n+5 4.设问题规模为N时,某递归算法的时间复杂度记为T(N),已知T(1)=1, T(N)=2T(N/2)+N/2,用O表示的时间复杂度为( C )。 A.O(logN) B.O(N) C.O(NlogN) D.O(N2logN) 5.直接或间接调用自身的算法称为( B )。 A.贪心算法B.递归算法 C.迭代算法D.回溯法 6.Fibonacci数列中,第4个和第11个数分别是( D )。 A.5,89 B.3,89 C.5,144 D.3,144 7.在有8个顶点的凸多边形的三角剖分中,恰有( B )。 A.6条弦和7个三角形B.5条弦和6个三角形 C.6条弦和6个三角形D.5条弦和5个三角形 8.一个问题可用动态规划算法或贪心算法求解的关键特征是问题的( B )。 A.重叠子问题B.最优子结构性质 C.贪心选择性质D.定义最优解 9.下列哪个问题不用贪心法求解( C )。 A.哈夫曼编码问题B.单源最短路径问题 C.最大团问题D.最小生成树问题 10.下列算法中通常以自底向上的方式求解最优解的是( B )。 A.备忘录法B.动态规划法 C.贪心法D.回溯法 11.下列算法中不能解决0/1背包问题的是( A )。 A.贪心法B.动态规划 C.回溯法D.分支限界法 12.下列哪个问题可以用贪心算法求解( D )。

回溯法和分支限界法解决背包题

0-1背包问题 计科1班朱润华 32 方法1:回溯法 一、回溯法描述: 用回溯法解问题时,应明确定义问题的解空间。问题的解空间至少包含问题的一个(最优)解。对于0-1背包问题,解空间由长度为n的0-1向量组成。该解空间包含对变量的所有0-1赋值。例如n=3时,解空间为:{(0,0,0),(0,1,0),(0,0,1),(1,0,0),(0,1,1),(1,0,1),(1,1,0),(1,1,1)}然后可将解空间组织成树或图的形式,0-1背包则可用完全二叉树表示其解空间给定n种物品和一背包。物品i的重量是wi,其价值为vi,背包的容量为C。问:应如何选择装入背包的物品,使得装入背包中物品的总价值最大 形式化描述:给定c >0, wi >0, vi >0 , 1≤i≤n.要求找一n元向量(x1,x2,…,xn,), xi∈{0,1}, ∑ wi xi≤c,且∑ vi xi达最大.即一个特殊的整数规划问题。 二、回溯法步骤思想描述: 0-1背包问题是子集选取问题。0-1 背包问题的解空间可以用子集树表示。在搜索解空间树时,只要其左儿子节点是一个可行节点,搜索就进入左子树。当右子树中有可能含有最优解时,才进入右子树搜索。否则,将右子树剪去。设r是当前剩余物品价值总和,cp是当前价值;bestp是当前最优价值。当cp+r<=bestp时,可剪去右子树。计算右子树上界的更好的方法是将剩余物品依次按其单位价值排序,然后依次装入物品,直至

装不下时,再装入物品一部分而装满背包。 例如:对于0-1背包问题的一个实例, n=4,c=7,p=[9,10,7,4],w=[3,5,2,1]。这4个物品的单位重量价值分别为[3,2,3,5,4]。以物品单位重量价值的递减序装入物品。先装入物品4,然后装入物品3和1.装入这3个物品后,剩余的背包容量为1,只能装的物品2。由此得一个解为[1,,1,1],其相应价值为22。尽管这不是一个可行解,但可以证明其价值是最优值的上界。因此,对于这个实例,最优值不超过22。 在实现时,由Bound计算当前节点处的上界。类Knap的数据成员记录解空间树中的节点信息,以减少参数传递调用所需要的栈空间。在解空间树的当前扩展节点处,仅要进入右子树时才计算上界Bound,以判断是否可将右子树剪去。进入左子树时不需要计算上界,因为上界预期父节点的上界相同。 三、回溯法实现代码: #include "" #include using namespace std; template class Knap { template friend Typep Knapsack(Typep [],Typew [],Typew,int);

分支限界法实现单源最短路径问题

实验五分支限界法实现单源最短路径 一实验题目:分支限界法实现单源最短路径问题 二实验要求:区分分支限界算法与回溯算法的区别,加深对分支限界法的理解。 三实验内容:解单源最短路径问题的优先队列式分支限界法用一极小堆来存储活结点表。其优先级是结点所对应的当前路长。算法从图G的源顶点s和空优先队列开始。 结点s被扩展后,它的儿子结点被依次插入堆中。此后,算法从堆中取出具有最小当前路长的结点作为当前扩展结点,并依次检查与当前扩展结点相邻的所有顶点。如果从当前扩展结点i到顶点j有边可达,且从源出发,途经顶点i再到顶点j的所相应的路径的长度小于当前最优路径长度,则将该顶点作为活结点插入到活结点优先队列中。这个结点的扩展过程一直继续到活结点优先队列为空时为止。 四实验代码 #include using namespace std; const int size = 100; const int inf = 5000; //两点距离上界 const int n = 6; //图顶点个数加1 int prev[n]; //图的前驱顶点 int dist[] = {0,0,5000,5000,5000,5000}; //最短距离数组 int c[n][n] = {{0,0,0,0,0,0},{0,0,2,3,5000,5000}, //图的邻接矩阵 {0,5000,0,1,2,5000},{0,5000,5000,0,9,2}, {0,5000,5000,5000,0,2},{0,5000,5000,5000,5000,0}}; const int n = 5; //图顶点个数加1 int prev[n]; //图的前驱顶点 int dist[] = {0,0,5000,5000,5000}; int c[][n] = {{0,0,0,0,0},{0,0,2,3,5000},{0,5000,0,1,2},{0,5000,5000,0,9}, {0,5000,5000,5000,0}};

C语言版贪心算法背包问题

#include<> #define N 100 typedef struct bao{ int num; float w; float v; }; typedef struct avg{ int num; ( float val; float w; float v; }; struct bao b[N]; struct avg d[N]; int n; float c; ^ void Sort() { int i,j,k; struct avg temp[N]; for(i=0;i

float x[N],sum = 0; for(i=0;ic) break; x[d[i].num] = 1; sum += d[i].v; c -= d[i].w; } if(i

分支限界法实验(最优装载问题)

算法分析与设计实验报告第八次附加实验

for(int i=1;i

完整代码(分支限界法) //分支限界法求最优装载 #include #include #include #include using namespace std; class QNode { friend void Enqueue(queue&,int,int,int,int,QNode *,QNode *&,int *,bool); friend void Maxloading(int *,int,int,int *); private: QNode *parent; //指向父节点的指针 bool LChild; //左儿子标志,用来表明自己是否为父节点的左儿子 int weight; //节点所相应的载重量 }; void Enqueue(queue&Q,int wt,int i,int n,int bestw,QNode *E,QNode *&bestE,int bestx[],bool ch) { //将活节点加入到队列中 if(i==n) //到达叶子节点 { if(wt==bestw) //确保当前解为最优解 { bestE=E; bestx[n]=ch; } return; } //当不为叶子节点时,加入到队列中,并更新载重、父节点等信息 QNode *b; b=new QNode; b->weight=wt; b->parent=E; b->LChild=ch; Q.push(b); } void Maxloading(int w[],int c,int n,int bestx[]) //其中w[]为重量数组| { // c为船的总载重量,n为节点数 //初始化 queue Q; //活节点队列

回溯法和分支限界法解决0-1背包题

0-1背包问题 计科1班朱润华2012040732 方法1:回溯法 一、回溯法描述: 用回溯法解问题时, 应明确定义问题的解空间。 问题的解空间至少包含问题的一个 (最 优)解。对于0-1背包问题,解空间由长度为 n 的0-1向量组成。该解空间包含对变量的所 有 0-1 赋值。例如 n=3 时,解空间为: {(0, 0, 0), (0, 1, 0), (0, 0, 1) , (1, 0, 0), (0, 1, 1), (1, 0, 1), (1, 1, 0), (1 , 1, 1) 然后可将解空间组织成树或图的形式, 0-1背包则可用完全二叉树表示其解空间给定 n 种物品和一背包。物品i 的重量是wi ,其价 值为vi ,背包的容量为 C 。问:应如何选择装入背包的物品,使得装入背包中物品的总价值 最大? 形式化描述:给定 c >0, wi >0, vi >0 , 1 w i < n.要求找一 n 元向量(x1,x2,…,xn,), xi € {0,1}, ? 刀wi xi w c,且刀vi xi 达最大.即一个特殊的整数规划问题。 二、回溯法步骤思想描述: 0-1背包问题是子集选取问题。0-1背包问题的解空间可以用子集树表示。在搜索解空 间树时,只要其 左儿子节点是一个可行节点, 搜索就进入左子树。当右子树中有可能含有最 优解时,才进入右子树搜索。否则,将右子树剪去。设 r 是当前剩余物品价值总和, cp 是 当前价值;bestp 是当前最优价值。当 cp+r<=bestp 时,可剪去右子树。计算右子树上界的 更好的方法是将剩余物品依次按其单位价值排序, 然后依次装入物品, 直至装不下时,再装 入物品一部分而装满背包。 例如:对于 0-1 背包问题的一个实例,n=4,c=7,p=[9,10,7,4],w=[3,5,2,1] 品的单位重量价值分别为[3,2,3,5,4]。以物品单位重量价值的递减序装入物品。 品4,然后装入物品3和1.装入这3个物品后,剩余的背包容量为1,只能装 由此得一个解为[1,0.2,1,1],其相应价值为22。尽管这不是一个可行解,但可以证明其价 值是最优值的上界。因此,对于这个实例,最优值不超过 在实现时,由 Bound 计算当前节点处的上界。类 Knap 的数据成员记录解空间树中的节 点信息,以减少参数传递调用所需要的栈空间。 在解空间树的当前扩展节点处, 仅要进入右 子树时才计算上界 Bound,以判断是否可将右子树剪去。进入左子树时不需要计算上界,因 为上界预期父节点的上界相同。 三、回溯法实现代码: #i nclude "stdafx.h" #in clude using n ames pace std; temp late class Knap { temp latevciass Typ ew,class Typep> friend Typep Knap sack(T ypep [],T ypew [],T yp ew,i nt); private: Typep Boun d(i nt i); 。这4个物 先装入物 0.2的物品2。 22。

0037算法笔记——【分支限界法】最大团问题

问题描述 给定无向图G=(V, E),其中V是非空集合,称为顶点集;E 是V中元素构成的无序二元组的集合,称为边集,无向图中的边均是顶点的无序对,无序对常用圆括号“( )”表示。如果U∈V,且对任意两个顶点u,v∈U有(u, v)∈E,则称U是G的完全子图(完全图G就是指图G的每个顶点之间都有连边)。G的完全子图U是G的团当且仅当U不包含在G的更大的完全子图中。G的最大团是指G中所含顶点数最多的团。 如果U∈V且对任意u,v∈U有(u, v)不属于E,则称U是G 的空子图。G的空子图U是G的独立集当且仅当U不包含在G的更大的空子图中。G的最大独立集是G中所含顶点数最多的独立集。 对于任一无向图G=(V, E),其补图G'=(V', E')定义为:V'=V,且(u, v)∈E'当且仅当(u, v)∈E。 如果U是G的完全子图,则它也是G'的空子图,反之亦然。因此,G的团与G'的独立集之间存在一一对应的关系。特殊地,U是G的最大团当且仅当U是G'的最大独立集。 例:如图所示,给定无向图G={V, E},其中V={1,2,3,4,5},E={(1,2), (1,4), (1,5),(2,3), (2,5), (3,5), (4,5)}。根据最大团(MCP)定义,子集{1,2}是图G的一个大小为2的完全子图,但不是一个团,因为它包含于G的更大的完全子图{1,2,5}之中。{1,2,5}是G的一个最大团。{1,4,5}和{2,3,5}也是G的最大团。右侧图是无向图G的补

图G'。根据最大独立集定义,{2,4}是G的一个空子图,同时也是G的一个最大独立集。虽然{1,2}也是G'的空子图,但它不是G'的独立集,因为它包含在G'的空子图{1,2,5}中。{1,2,5}是G'的最大独立集。{1,4,5}和{2,3,5}也是G'的最大独立集。 算法设计 最大团问题的解空间树也是一棵子集树。子集树的根结点是初始扩展结点,对于这个特殊的扩展结点,其cliqueSize的值为0。算法在扩展内部结点时,首先考察其左儿子结点。在左儿子结点处,将顶点i加入到当前团中,并检查该顶点与当前团中其它顶点之间是否有边相连。当顶点i与当前团中所有顶点之间都有边相连,则相应的左儿子结点是可行结点,将它加入到子集树中并插入活结点优先队列,否则就不是可行结点。 接着继续考察当前扩展结点的右儿子结点。当 upperSize>bestn时,右子树中可能含有最优解,此时将右儿子结点加入到子集树中并插入到活结点优先队列中。算法的while循环的终止条件是遇到子集树中的一个叶结点(即n+1层结点)成为当前扩展结点。

背包问题(贪心算法)

算法分析与设计实验报告 第 4 次实验

}

附录:完整代码 #include #include #include struct node{ float value; float weight; }; float Value,curvalue=0; float Weight,curweight=0; //按价重比冒泡排序 void sort(node Node[],int M){ int i,j; node temp; for(i=0;i

用回溯法和队列式分支限界算法求解0-1背包问题

华北水利水电学院数据结构与算法分析实验报告2009 ~2010 学年第 1 学期2009 级计算机专业 班级:200915326 学号:200915326 姓名:郜莉洁 一、实验题目: 分别用回溯法和分支限界法求解0-1背包问题 二、实验内容: 0-1背包问题:给定n种物品和一个背包。物品i的重量是Wi,其价值为Vi,背包的容量为C。应如何选择装入背包的物品,使得装入背包中物品的总价值最大? 在选择装入背包的物品时,对每种物品i只有2种选择,即装入背包或不装入背包。不能将物品i装入背包多次,也不能只装入部分的物品i。 三、程序源代码: A:回溯法: // bag1.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include #define MaxSize 100 //最多物品数 int limitw; //限制的总重量 int maxwv=0; //存放最优解的总价值 int maxw; int n; //实际物品数 int option[MaxSize]; // 存放最终解 int op[MaxSize]; //存放临时解 struct { int weight; int value; }a[MaxSize]; //存放物品数组 void Knap( int i, int tw, int tv) //考虑第i个物品 { int j; if(i>=n) //找到一个叶子结点 { if (tw<=limitw && tv>maxwv) //找到一个满足条件地更优解,保存它 { maxwv=tv; maxw=tw; for(j=0;j

贪心算法背包问题

算法设计与分析实验报告 题目:贪心算法背包问题 专业:JA V A技术xx——xxx班 学号: 姓名: 指导老师:

实验三:贪心算法背包问题 一、实验目的与要求 1、掌握背包问题的算法 2、初步掌握贪心算法 二、实验题: 问题描述:与0-1背包问题相似,给定n种物品和一个背包。物品i的重量是wi,其价值为vi,背包的容量为c。与0-1背包问题不同的是,在选择物品i装入背包时,背包问题的解决可以选择物品i的一部分,而不一定要全部装入背包,1< i < n。 三、实验代码 import java.awt.*; import java.awt.event.*; import javax.swing.*; public class er extends JFrame { private static final long serialVersionUID = -1508220487443708466L; private static final int width = 360;// 面板的宽度 private static final int height = 300;// 面板的高度 public int M; public int[] w; public int[] p; public int length; er() { // 初始Frame参数设置 this.setTitle("贪心算法"); setDefaultCloseOperation(EXIT_ON_CLOSE); setSize(width, height); Container c = getContentPane(); c.setLayout(new BoxLayout(c, BoxLayout.Y_AXIS)); setLocation(350, 150); // 声明一些字体样式 Font topF1 = new Font("宋体", Font.BOLD, 28); Font black15 = new Font("宋体", Font.PLAIN, 20); Font bold10 = new Font("宋体", Font.BOLD, 15); // 声明工具栏及属性设置 JPanel barPanel = new JPanel(); JMenuBar topBar = new JMenuBar(); topBar.setLocation(1, 1); barPanel.add(topBar); // 面板1和顶部标签属性设置 JPanel p1 = new JPanel(); JLabel topLabel = new JLabel("背包问题");

回溯法实验(最优装载)

算法分析与设计实验报告第二次附加实验 )用可行性约束函数可剪去不满足约束条件

附录: 完整代码(贪心法) //回溯法递归求最优装载问题#include #include #include using namespace std; template class Loading { public: void Backtrack(int i);

int n, //集装箱数 *x, //当前解 *bestx; //当前最优解 Type *w, //集装箱重量数组 c, //第一艘轮船的载重量 cw, //当前载重量 bestw, //当前最优载重量 r; //剩余集装箱重量 }; template void Loading::Backtrack(int i); template //参数为:w[]各物品重量数组,c为第一艘轮船的载重量,n为物品数量,bestx[]数组为最优解 Type MaxLoading(Type w[],Type c,int n,int bestx[]); int main() { int n=3,m; int c=50,c2=50; int w[4]={0,10,40,40}; int bestx[4]; clock_t start,end,over; //计算程序运行时间的算法 start=clock(); end=clock(); over=end-start; start=clock(); m=MaxLoading(w,c,n,bestx); //调用MaxLoading函数 cout<<"轮船的载重量分别是:"< using namespace std; template class Knap { template friend Typep Knapsack(Typep [],Typew [],Typew,int); private: Typep Bound(int i);

相关文档
最新文档