您好,欢迎来到爱问旅游网。
搜索
您的当前位置:首页装载问题5种解决方案

装载问题5种解决方案

来源:爱问旅游网
算法分析与设计

2016/2017(2)

实验题目装载问题5种解法

学生姓名 学生学号 学生班级 任课教师 提交日期2017

计算机科学与技术学

目录

一问题定义 ........................................................................................................................................2 二解决方案 ........................................................................................................................................2

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

1.1算法分析 ......................................................................................................................2 1.2代码 ..............................................................................................................................2 1。3运行结果 ................................................................................................................ 12 2队列式分支限界法求解....................................................................................................... 12

2。1算法分析 ................................................................................................................ 12 2。2代码 ........................................................................................................................ 13 2.3测试截图 ................................................................................................................... 21 3回朔法-迭代 ......................................................................................................................... 21

3.1算法分析 ................................................................................................................... 21 3。2代码 ........................................................................................................................ 21 3.3测试截图 ....................................................................................................................25 4回朔法-递归 ..........................................................................................................................25

4。1算法分析 .................................................................................................................25 4。2代码 .........................................................................................................................25 4.3测试截图 ................................................................................................................... 30 5贪心算法 .............................................................................................................................. 30

5.1算法分析 ................................................................................................................... 30 5.2代码 ........................................................................................................................... 30 5。3测试截图 ................................................................................................................ 33

算法分析与设计

一问题定义

有一批共有 n 个集装箱要装上两艘载重量分别为 c1 和 c2 的轮船,其中集装箱 i 的重量为 w[i], 且重量之和小于(c1 + c2)。装载问题要求确定是否存在一个合理的装载方案可将这 n 个集装箱装上这两艘轮船。如果有,找出一种装载方案.

二解决方案

1优先队列式分支限界法求解 1.1算法分析

活结点x在优先队列中的优先级定义为从根结点到结点x的路径所相应的载重量再加上剩余集装箱的重量之和。优先队列中优先级最大的活结点成为下一个扩展结点.以结点x为根的子树中所有结点相应的路径的载重量不超过它的优先级。子集树中叶结点所相应的载重量与其优先级相同。在优先队列式分支限界法中,一旦有一个叶结点成为当前扩展结点,则可以断言该叶结点所相应的解即为最优解。此时可终止算法.

1.2代码

1。2-1////MaxHeap.h

templatepublic:

MaxHeap(int MaxHeapSize = 10); ~MaxHeap() {delete [] heap;}

int Size() const {return CurrentSize;}

2 / 33

算法分析与设计

T Max()

{ //查找 if (CurrentSize == 0) {

throw OutOfBounds(); }

return heap[1]; }

MaxHeap& Insert(const T& x); //增 MaxHeap& DeleteMax(T& x); //删

void Initialize(T a[], int size, int

private:

int CurrentSize, MaxSize; T *heap; // element array };

templateMaxHeap〈T〉::MaxHeap(int MaxHeapSize) {// Max heap constructor。 MaxSize = MaxHeapSize; heap = new T[MaxSize+1]; CurrentSize = 0; }

template

MaxHeap& MaxHeap〈T〉::Insert(const T& x) {// Insert x into the max heap.

3 / 33

ArraySize); 算法分析与设计

if (CurrentSize == MaxSize) {

cout〈<\"no space!\"〈〈endl; return *this; }

// 寻找新元素x的位置

// i——初始为新叶节点的位置,逐层向上,寻找最终位置 int i = ++CurrentSize;

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

// i不是根节点,且其值大于父节点的值,需要继续调整 heap[i] = heap[i/2]; // 父节点下降

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

heap[i] = x; return *this; }

template

MaxHeap& MaxHeap{// Set x to max element and delete max element from heap。 // check if heap is empty if (CurrentSize == 0) {

cout〈<\"Empty heap!\"<4 / 33

算法分析与设计

x = heap[1]; // 删除最大元素 // 重整堆

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

// find place for y starting at root int i = 1, // current node of heap ci = 2; // child of i

while (ci <= CurrentSize) {

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

if (ci < CurrentSize && heap[ci] 〈 heap[ci+1]) {

ci++; }

// y的值大于等于孩子节点吗? if (y >= heap[ci]) {

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

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

heap[i] = heap[ci]; // 大于父节点的孩子节点上升 i = ci; // 向下一层,继续搜索正确位置

ci *= 2; }

heap[i] = y;

5 / 33

算法分析与设计

return *this; }

template〈class T>

void MaxHeap::Initialize(T a[], int size,int ArraySize) {// Initialize max heap to array a。 delete [] heap; heap = a;

CurrentSize = size; MaxSize = ArraySize;

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

T y = heap[i]; // 子树根节点元素 // find place to put y

int c = 2*i; // parent of c is target // location for y while (c <= CurrentSize) {

// heap[c] should be larger sibling if (c < CurrentSize && heap[c] [c+1])

{

c++; }

// can we put y in heap[c/2]? if (y 〉= heap[c]) {

break; // yes

6 / 33

< heap

算法分析与设计

}

// no

heap[c/2] = heap[c]; // move child up c *= 2; // move down a level }

heap[c/2] = y; } }

1.2—2///6d3-2.cpp

//装载问题 优先队列式分支限界法求解 #include \"stdafx.h\" #include ”MaxHeap。h” #include 〈iostream> using namespace std;

const int N = 4;

class bbnode;

template〈class Type〉 class HeapNode {

templatefriend void AddLiveNode(MaxHeap〈HeapNode

friend Type MaxLoading(Type w[],Type c,int n,int bestx[]); 7 / 33

* 算法分析与设计

public:

operator Type() const{return uweight;} private:

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

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

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

class bbnode {

template〈class Type〉

friend void AddLiveNode(MaxHeap〈HeapNode>& H,bbnode *E,Type wt,bool ch,int lev); template

friend Type MaxLoading(Type w[],Type c,int n,int bestx[]); friend class AdjacencyGraph;

private:

bbnode *parent; //指向父节点的指针 bool LChild; //左儿子节点标识 };

template

void AddLiveNode(MaxHeap〈HeapNode〈Type〉〉& H,bbnode *E,Type wt,bool ch,int lev);

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

8 / 33

算法分析与设计

int main() {

float c = 70;

float w[] = {0,20,10,26,15};//下标从1开始 int x[N+1]; float bestw;

cout<<\"轮船载重为:\"<〈c〈〈endl; cout<〈\"待装物品的重量分别为:\"<〈endl; for(int i=1; i<=N; i++) {

cout<cout〈〈endl;

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

cout<〈”分支限界选择结果为:”<〈endl; for(int i=1; i〈=4; i++) {

cout<〈x[i]<〈” \"; }

cout<cout〈<\"最优装载重量为:”<〈bestw<return 0; }

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

9 / 33

算法分析与设计

template〈class Type>

void AddLiveNode(MaxHeap>& HType wt,bool ch,int lev) {

bbnode *b = new bbnode; b—〉parent = E; b—>LChild = ch; HeapNode〈Type〉 N;

N。uweight = wt; N.level = lev; N.ptr = b; H。Insert(N); }

//优先队列式分支限界法,返回最优载重量,bestx返回最优解 template〈class Type>

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

//定义最大的容量为1000

MaxHeap〈HeapNode〈Type〉> H(1000);

//定义剩余容量数组

Type *r = new Type[n+1]; r[n] = 0;

for(int j=n-1; j>0; j—-) {

r[j] = r[j+1] + w[j+1]; }

10 / 33

,bbnode *E,

算法分析与设计

//初始化

int i = 1;//当前扩展节点所处的层 bbnode *E = 0;//当前扩展节点 Type Ew = 0; //扩展节点所相应的载重量

//搜索子集空间树

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

//检查当前扩展节点的儿子节点 if(Ew+w[i]<=c) {

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

//右儿子节点

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

//取下一扩展节点 HeapNode〈Type> N; H.DeleteMax(N);//非空 i = N.level; E = N.ptr;

Ew = N。uweight - r[i—1]; }

//构造当前最优解

for(int j=n; j〉0; j—-) {

bestx[j] = E—>LChild; E = E-〉parent;

11 / 33

算法分析与设计

}

return Ew; }

1。3运行结果

2队列式分支限界法求解 2。1算法分析

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

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

节点的左子树表示将此集装箱装上船,右子树表示不将此集装箱装上船.设bestw是当前最优解;ew是当前扩展结点所相应的重量;r是剩余集装箱的重量。则当ew+r为了在算法结束后能方便地构造出与最优值相应的最优解,算法必须存储相应子集树中从活结点到根结点的路径。为此目的,可在每个结点处设置指向其父结点的指针,并设置左、右儿子标志。找到最优值后,可以根据parent回溯到根节点,找到最优解。

12 / 33

2。2代码

22-1////Queue。h

#include〈iostream> using namespace std; template 〈class T〉 class Queue {

public:

Queue(int MaxQueueSize=50); ~Queue(){delete [] queue;}

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

{return ( ( (rear+1)%MaxSize==front )?1:0);} T Top() const; T Last() const;

Queue& Add(const T& x); Queue〈T>& AddLeft(const T& x); Queue& Delete(T &x); void Output(ostream& out)const; int Length(){return (rear—front);} private:

int front; int rear; int MaxSize; T *queue; };

template〈class T〉

13 / 33

算法分析与设计

算法分析与设计

QueueMaxSize=MaxQueueSize+1; queue=new T[MaxSize]; front=rear=0; }

template T Queue〈T〉::Top()const {

if(IsEmpty()) {

cout〈〈”queue:no element,no!\"〈〈endl; return 0; }

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

template〈class T〉

T Queue〈T〉 ::Last()const {

if(IsEmpty()) {

cout〈<\"queue:no element”〈else return queue[rear]; }

template〈class T〉

14 / 33

算法分析与设计

Queue〈T>& Queue〈T>::Add(const T& x) {

if(IsFull())cout<<”queue:no memory\"<rear=(rear+1)% MaxSize; queue[rear]=x; }

return *this; }

template

Queue& Queue〈T>::AddLeft(const T& x) {

if(IsFull())cout〈〈”queue:no memory\"〈〈endl; else {

front=(front+MaxSize-1)% MaxSize; queue[(front+1)% MaxSize]=x; }

return *this; }

templateQueue& Queueif(IsEmpty())cout<〈\"queue:no element(delete)\"<front=(front+1) % MaxSize;

15 / 33

x=queue[front]; }

return *this; }

template〈class T>

void Queue for(int i=rear%MaxSize;i>=(front+1)%MaxSize;i—-) out〈template〈class T>

ostream& operator 〈< (ostream& out,const Queue〈T〉&{x.Output(out);return out;}

2。2—2////6d3-1.cpp

//装载问题 队列式分支限界法求解 #include \"stdafx.h” #include \"Queue.h” #include const int N = 4;

template16 / 33

算法分析与设计

x) 算法分析与设计

templatefriend void EnQueue(Queue〈QNode*>&Q,Type wt,int i,int n,Type bestw,QNode*E,QNode *&bestE,int bestx[],bool ch);

template〈class Type〉

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

private:

QNode *parent; //指向父节点的指针 bool LChild; //左儿子标识 Type weight; //节点所相应的载重量 };

template〈class Type>

void EnQueue(Queue〈QNode〈Type〉*>&Q,Type wt,int i,int n,Type bestw,QNode〈Type〉*E,QNode〈Type> *&bestE,int bestx[],bool ch);

template

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

int main() {

float c = 70;

float w[] = {0,20,10,26,15};//下标从1开始 int x[N+1]; float bestw;

cout〈〈”轮船载重为:”<17 / 33

算法分析与设计

for(int i=1; i<=N; i++) {

cout〈〈w[i]<<\" \"; }

cout<bestw = MaxLoading(w,c,N,x);

cout〈<”分支限界选择结果为:”<〈endl; for(int i=1; i<=4; i++) {

cout<cout<〈endl;

cout〈〈\"最优装载重量为:”<return 0; }

//将活节点加入到活节点队列Q中 templatevoid EnQueue(Queue*>&Q,Type wt,int i,int n,Type QNode*E,QNode〈Type〉 *&bestE,int bestx[],bool ch) {

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

if(wt == bestw) {

//当前最优装载重量 bestE = E;

bestx[n] = ch;

18 / 33

bestw,算法分析与设计

} return; } //非叶节点 QNode *b; b = new QNode〈Type〉; b->weight = wt; b—>parent = E; b->LChild = ch; Q.Add(b); }

templateType MaxLoading(Type w[],Type c,int n,int bestx[]) {//队列式分支限界法,返回最优装载重量,bestx返回最优解 //初始化

Queue〈QNode*〉 Q; //活节点队列

Q。Add(0); //同层节点尾部标识 int i = 1; //当前扩展节点所处的层 Type Ew = 0, //扩展节点所相应的载重量 bestw = 0, //当前最优装载重量 r = 0; //剩余集装箱重量 for(int j=2; j<=n; j++) {

r += w[j]; }

QNode *E = 0, //当前扩展节点 *bestE; //当前最优扩展节点

19 / 33

算法分析与设计

//搜索子集空间树 while(true) {

//检查左儿子节点

Type wt = Ew + w[i]; if(wt <= c)//可行节点 {

if(wt>bestw) {

bestw = wt; }

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

//检查右儿子节点 if(Ew+r〉bestw) {

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

Q.Delete(E);//取下一扩展节点 if(!E)//同层节点尾部 {

if(Q。IsEmpty()) {

break; }

Q.Add(0); //同层节点尾部标识 Q.Delete(E); //取下一扩展节点 i++; //进入下一层 r-=w[i]; //剩余集装箱重量

20 / 33

算法分析与设计

}

Ew =E—〉weight; //新扩展节点所对应的载重量 }

//构造当前最优解

for(int j=n—1; j〉0; j--) {

bestx[j] = bestE—>LChild; bestE = bestE-〉parent; }

return bestw; }

2.3测试截图 3回朔法—迭代 3.1算法分析

用回溯法解装载问题时,用子集树表示其解空间显然是最合适的。可行性约束条件重量之和小于(c1 + c2)可剪去不满足约束条件的子树用cw记当前的装载重量,即cw=(w1x1+w2x2+...+wjxj),当cw〉c1时,以节点Z为根的子树中所有节点都不满足约束条件,因而该子树中解均为不可行解,故可将该子树剪去。

3。2代码

#include 〈iostream〉 using namespace std;

template〈class Type〉

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

21 / 33

算法分析与设计

{

int n=3,m; int c=50,c2=50;

int w[4]={0,10,40,40}; int bestx[4];

m=MaxLoading(w, c, n, bestx);

cout〈〈”轮船的载重量分别为:”〈cout<〈”待装集装箱重量分别为:”<for (int i=1;i〈=n;i++) {

cout〈cout〈〈endl;

cout〈〈”回溯选择结果为:”〈〈endl; cout<<\"m(1)=\"〈〈m<〈endl; cout<〈\"x(i)=”;

for (int i=1;i〈=n;i++) {

cout<cout<int m2=0;

22 / 33

算法分析与设计

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

m2=m2+w[j]*(1-bestx[j]); }

cout<〈”m(2)=\"〈if(m2〉c2) {

cout<<\"因为m(2)大于c(2),所以原问题无解!\"<return 0; }

template 〈class Type〉

Type MaxLoading(Type w[],Type c,int n,int bestx[])//迭代回溯法,返回最优载重量及其相应解,初始化根结点 {

int i=1;//当前层,x[1:i—1]为当前路径 int *x=new int[n+1];

Type bestw=0, //当前最优载重量 cw=0, //当前载重量 r=0; //剩余集装箱重量

for (int j=1;j〈=n;j++) {

r+=w[j]; }

while(true)//搜索子树

23 / 33

算法分析与设计

{

while(i<=n &&cw+w[i]〈=c)//进入左子树 {

r—=w[i]; cw+=w[i]; x[i]=1; i++; }

if (i>n)//到达叶结点 {

for (int j=1;j<=n;j++) { bestx[j]=x[j]; } bestw=cw; }

else//进入右子树 { r-=w[i]; x[i]=0; i++; }

while (cw+r<=bestw) { //剪枝回溯 i——;

while (i〉0 && !x[i]) {

r+=w[i]; i——; } //从右子树返回 if (i==0) {

24 / 33

算法分析与设计

delete []x; return bestw; } x[i]=0; cw—=w[i]; i++; } } }

3。3测试截图 4回朔法—递归 4.1算法分析

与回朔法-迭代的相同,以下代码只是更改了具体的实现过程

4。2代码

#include 〈iostream> using namespace std;

template 〈class Type〉 class Loading {

//friend Type MaxLoading(Type[],Type,int,int //private: public:

void Backtrack(int i);

int n, //集装箱数 25 / 33

[]);

算法分析与设计

*x, //当前解 *bestx; //当前最优解 Type *w, //集装箱重量数组

c, //第一艘轮船的载重量 cw, //当前载重量 bestw, //当前最优载重量 r; //剩余集装箱重量 };

template 〈class Type>

void Loading ::Backtrack (int i);

template

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];

m=MaxLoading(w, c, n, bestx);

cout〈<\"轮船的载重量分别为:\"<〈endl;

cout<〈”c(1)=\"〈〈c〈<”,c(2)=\"〈〈c2〈〈endl;

cout<〈”待装集装箱重量分别为:”〈〈endl; cout〈<\"w(i)=”;

26 / 33

算法分析与设计

for (int i=1;i〈=n;i++) {

cout<cout<cout<〈\"回溯选择结果为:\"<〈endl; cout<〈\"m(1)=”〈for (int i=1;i〈=n;i++) {

cout〈〈bestx[i]〈〈” ”; }

cout<int m2=0;

for (int j=1;j〈=n;j++) {

m2=m2+w[j]*(1—bestx[j]); }

cout<〈”m(2)=”〈〈m2<〈endl;

if(m2>c2) {

cout<〈”因为m(2)大于c(2),所以原问题无解!\"<〈endl; }

return 0; }

27 / 33

算法分析与设计

template 〈class Type>

void Loading ::Backtrack (int i)// 搜索第i层结点 {

if (i > n)// 到达叶结点 {

if (cw〉bestw) {

for(int j=1;j〈=n;j++) {

bestx[j]=x[j];//更新最优解 bestw=cw; } } return; }

r—=w[i];

if (cw + w[i] <= c) // 搜索左子树 {

x[i] = 1; cw += w[i]; Backtrack(i+1); cw-=w[i]; }

if (cw + r > bestw) {

x[i] = 0; // 搜索右子树 Backtrack(i + 1); }

28 / 33

算法分析与设计

r+=w[i]; }

templateType MaxLoading(Type w[], Type c, int n, int bestx[])//返回最优载重量 {

Loading〈Type>X; //初始化X

X.x=new int[n+1]; X。w=w; X.c=c; X.n=n; X.bestx=bestx; X.bestw=0; X.cw=0; //初始化r X.r=0;

for (int i=1;i〈=n;i++) {

X。r+=w[i]; }

X.Backtrack(1); delete []X.x; return X。bestw; }

29 / 33

算法分析与设计

4。3测试截图 5贪心算法 5。1算法分析

最优子结构性质:设(x1,x2,……xn)是最优装载问题的满足贪心选择性质的最优解,则易知,x1=1,(x2,x3,……xn)是轮船载重量为c—w1,待装船集装箱为{2,3,……n}时相应最优装载问题的最优解。因此,最优装载问题具有最优子结构性质。

求解过程:最优装载问题可用贪心算法求解。采用重量最轻者先装的贪心选择策略,可产生最优装载问题的最优解。

5.2代码

#include const int N = 4;

template void Swap(Type &x,Type &y);

template

void Loading(int x[], Type w[], Type c, int n);

template

void SelectSort(Type w[],int *t,int n);

int main() {

30 / 33

算法分析与设计

float c = 70;

float w[] = {0,20,10,26,15};//下标从1开始 int x[N+1];

cout〈〈\"轮船载重为:”<〈c<cout<〈w[i]〈〈\" \"; }

cout〈cout<<”贪心选择结果为:”〈〈endl; for(int i=1; i〈=N; i++) {

cout<cout<〈endl;

return 0; }

templatevoid Loading(int x[],Type w[], Type c, int n) {

int *t = new int [n+1];//存储排完序后w[]的原始索引 SelectSort(w, t, n);

for(int i=1; i〈=n; i++)

31 / 33

算法分析与设计

{

x[i] = 0;//初始化数组x[] }

for(int i=1; i〈=n && w[t[i]]<=c; i++) {

x[t[i]] = 1; c -= w[t[i]]; } }

template

void SelectSort(Type w[],int *t,int n) {

Type tempArray[N+1],temp;

memcpy(tempArray,w,(n+1)*sizeof(Type));//将w拷贝到临时数组tempArray中

int min;

for(int i=1;i〈=n;i++) {

t[i] = i; }

for(int i=1;imin=i;

for(int j=i+1;j〈=n;j++) {

if(tempArray[min]>tempArray[j]) {

32 / 33

算法分析与设计

min=j; } }

Swap(tempArray[i],tempArray[min]); Swap(t[i],t[min]); } }

template void Swap(Type &x,Type {

Type temp = x; x = y; y = temp; }

5.3测试截图

&y) 33 / 33

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- awee.cn 版权所有 湘ICP备2023022495号-5

违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务