算法装载问题

算法设计与分析实验报告-
1.实验要求:
将n个集装箱装上载重量为c1和c2的轮船,其中集装箱总重量<c1+c2,使用回溯法求出最优装载方案。

3.程序代码
package javaapplication1;
import java.io.*;
public class Main {
static int n;
static int []w;
static int c1,c2;
static int cw;
static int bestw;
static int r;
static int []x;
static int []bestx;
public static int maxloading(int[]ww,int cc,int[]xx){
w=ww;
c1=cc;
bestw=0;
cw=0;
x=new int[n+1];
bestx=xx;
r=0;
for(int i=1;i<=n;i++)
r+=w[i];
backtrack(1);
return bestw;
}
private static void backtrack(int 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]<=c1){
x[i]=1;
cw+=w[i];
backtrack(i+1);
cw-=w[i];
}
if(cw+r>bestw){
x[i]=0;
backtrack(i+1);
}
r+=w[i]; }
public static void main(String[] args) throws IOException {
BufferedReader read =new BufferedReader(new InputStreamReader(new FileInputStream("input.txt")));
String a=new String();
a=read.readLine();
n=Integer.parseInt(a);
System.out.println("集装箱个数: "+n);
x=new int[n+1];
String[]b=new String[n];
a=read.readLine();
System.out.println("集装箱重量: "+a);
b=a.split(",");
w=new int[n+1];
for(int i=1;i<=n;i++){
w[i]=Integer.parseInt(b[i-1]);
}
a=read.readLine();
c1=Integer.parseInt(a);
a=read.readLine();
c2=Integer.parseInt(a);
System.out.println("轮船载重量: "+c1+","+c2);
int result= maxloading(w,c1,x);
int max,temp;
for(int i=1;i<3;i++){
for(int j=2;j<3;j++){
if(w[i]>w[j]){
temp=w[i];
w[i]=w[j];
w[j]=temp;
}
}
}
if((w[3]>c1)&&(w[3]>c2)){
System.out.println("都不可装");
}
else{System.out.println("轮船1装载的集装箱:");
for (int u=1;u<n+1;u++)
if(bestx[u]==1)
System.out.println(u+" ");
if(r>(result+c2))
System.out.println("轮船1可装:"+result+" "+"轮船2装不完.");
else{
System.out.println("轮船2装载的集装箱:");
for (int u=1;u<n+1;u++)
if(bestx[u]==0)
System.out.println(u+" ");
System.out.println("最优装载--轮船1:"+result+" "+"轮船2:"+(r-result));
}
}
PrintWriter print=new PrintWriter(new OutputStreamWriter(new FileOutputStream("output.txt")));
if((w[3]>c1)&&(w[3]>c2)){
print.println("都不可装。

");
}
else{
print.println("轮船1装载的集装箱:");
for (int u=1;u<n+1;u++)
if(bestx[u]==1)
print.println(u+" ");
if(r>(result+c2))
print.println("轮船1可装:"+result+" "+"轮船2装不完。

");
else{
print.println("轮船2装载的集装箱:");
for (int u=1;u<n+1;u++)
if(bestx[u]==0)
print.println(u+" ");
print.println("最优装载--轮船1:"+result+" "+"轮船2:"+(r-result));
}
}
read.close();
print.close(); }
}
2.程序流程图:
4.程序截图
input.txt
output.txt。

合集下载

贪心算法之最优装载问题

贪心算法之最优装载问题

贪⼼算法之最优装载问题1. 问题描述: 给出n个物体,第i个物体的重量是Wi,选择尽量多的物体,使得总重量不超过C.2. 问题分析: 这是⼀个很典型的⽤贪⼼算法的题⽬.要想让装的物体越多,⾃然装的最轻的物体就越多.因此可以对物体的重量由⼩到⼤进⾏排序,然后依次装载即可.这就体现了贪⼼算法只顾眼前,但却可以得到最优解.3. 解决问题: 代码如下4. 1 #include <stdio.h>2 #include <stdlib.h>3 #include <string.h> //为了引⼊memcpy4/* 最有最优装载问题:5给出n个物体,第i个物体的重量为Wi,选择更多的物体,是物体的总量不超过C6*/7void swap(int *a,int *b)8 {9int temp;10 temp = *a;11 *a = *b;12 *b = temp;13 }14// 采⽤选择法对重量进⾏排序,t中记录的是从⼩到⼤的包的索引15void sortweight(int *w,int *t,int n)16 {17int i,j,temp;18int *w1 = malloc(sizeof(int)*n);19for(i =0; i < n; ++i)20 {21 t[i] = i;22 w1[i] = w[i];23 }24for(i = 0; i < n; ++i)25 {26 temp = i;27for(j = i+1; j < n; ++j)28 {29if(w1[j] < w1[temp])30 temp = j;31 }32if(temp != i)33 {34 swap(&w1[i],&w1[temp]); // 这个数据交换是必须的35 swap(&t[i],&t[temp]);36 }37 }38 }39int main()40 {41int n,weight_max,i;42int *w,*ind,*res;4344 printf("请输⼊商品的数量和商品的总载量\n");45 scanf("%d %d",&n,&weight_max);4647 w = malloc(sizeof(int)*n);48 ind = malloc(sizeof(int)*n);49 res = malloc(sizeof(int)*n);5051 printf("请依次输⼊商品的重量\n");52for(i = 0; i < n; ++i)53 scanf("%d",&w[i]);5455 sortweight(w,ind,n);5657for(i = 0; i < n && w[ind[i]] <= weight_max; ++i)58 {59 res[ind[i]] = 1;60 weight_max -= w[ind[i]];61 }62 printf("贪⼼算法求解后的结果是:\n");63for(i = 0; i < n; ++i)64 {65 printf("%d ",res[i]);66 }67 printf("\n");68return0;69 }4. 程序分析: 由于不要改变原始物体重量的值,所以在排序的时候要另外再开辟⼀个数组存储重量.并且另外开辟ind[]存放索引记录装载的顺序.ind[]存放的是重量数组中每个元素在这组数组中⼤⼩的顺序(索引).怎样在排序时记录索引需要在练习排序的时候注意下.。

用分支限界算法解装载问题详解

用分支限界算法解装载问题详解

用分支限界算法解装载问题详解一、实验目的1、理解分支限界法的概念,掌握分支限界法的基本要素。

2、掌握设计分支限界法的一般步骤,针对具体问题,能应用分支限界法求解二、实验内容1、问题描述:有一批共个集装箱要装上2艘载重量分别为C1和C2的轮船,其中集装箱i的重量为Wi,且w1+…+wn<= C1+ C2; 装载问题要求确定是否有一个合理的装载方案可将这个集装箱装上这2艘轮船。

如果有,找出一种装载方案。

2、数据输入:文件输入或键盘输入。

3、要求:1)完成上述问题的队列式分支限界法解决问题,时间为1 次课。

2)独立完成实验及实验报告。

三、实验步骤1、理解方法思想和问题要求。

2、采用编程语言实现题目要求。

3、上机输入和调试自己所写的程序。

4、附程序主要代码:#include <bits/stdc++、h>using namespace std;class MaxHeapQNode{public: MaxHeapQNode*parent; int lchild; int weight; int lev;};structcmp{ bool operator()(MaxHeapQNode *&a, MaxHeapQNode *&b)const { return a->weight < b->weight; }};int n;int c;int bestw;int w[100];int bestx[100];voidInPut(){ scanf("%d %d", &n, &c); for(int i =1; i <= n;++i)scanf("%d", &w[i]);}voidAddAliveNode(priority_queue<MaxHeapQNode *,vector<MaxHeapQNode *>, cmp> &q, MaxHeapQNode *E, int wt, int i, int ch){ MaxHeapQNode *p = new MaxHeapQNode; p->parent = E; p->lchild = ch; p->weight = wt; p->lev = i +1; q、push(p);}voidMaxLoading(){ priority_queue<MaxHeapQNode *,vector<MaxHeapQNode *>, cmp > q; // 大顶堆 //定义剩余重量数组r int r[n +1]; r[n] = 0; for(int j = n-j)r[j] = r[j +1] + w[j +1]; int i =1; MaxHeapQNode *E; int Ew = 0; while(i != n +1){ if(Ew + w[i] <= c){ AddAliveNode(q, E, Ew + w[i] + r[i], i,1); } AddAliveNode(q, E, Ew + r[i], i, 0); //取下一节点 E = q、top(); q、pop(); i = E->lev; Ew = E->weight1]; } bestw = Ew; for(int j = n; j > 0;j){ bestx[j] = E->lchild; E = E->parent; }}void OutPut(){ printf("最优装载量为 %d\n", bestw); printf("装载的物品为 \n"); for(int i =1; i <= n; ++i)if(bestx[i] ==1)printf("%d ", i);}int main(){ InPut(); MaxLoading(); OutPut();}5、实验结果:4、装载问题实验分析:1、将wt<=c和Ew+r>=bestw作为限界判定。

航空货运装载问题算法设计与研究

航空货运装载问题算法设计与研究

航空货运装载问题算法设计与研究航空货运装载问题算法设计与研究随着全球贸易的不断发展,航空货运业务也得到了迅猛的增长。

在航空货运过程中,货物的装载和排列方式对于提高运输效率至关重要。

航空货运装载问题是一种复杂的组合优化问题,涉及到如何在有限的空间中合理装载和排列各种尺寸、形状和重量的货物。

为了解决航空货运装载问题,研究人员们提出了许多算法和方法,并不断改进和优化。

本文将针对航空货运装载问题,从简到繁、由浅入深地探讨算法设计与研究的相关内容。

一、航空货运装载问题的定义与背景分析航空货运装载问题是指在给定的飞机货舱空间和重量限制条件下,如何优化装载和排列货物,使得运输效率最大化。

该问题可以被抽象为一个组合优化问题,需要通过算法求解。

要解决航空货运装载问题,需要考虑以下因素:1. 航空公司的货舱容量和重量限制:不同型号的飞机具有不同的货舱容量和重量限制,需要根据实际情况进行合理装载。

2. 货物的尺寸、形状和重量:货物的尺寸、形状和重量不同,对于装载的方式和顺序有着不同的要求。

3. 装卸过程中的安全性和稳定性:货物在装卸过程中需要保持安全和稳定,避免损坏和意外情况的发生。

二、航空货运装载问题的求解算法为了求解航空货运装载问题,研究人员们提出了多种算法和方法。

根据问题的复杂度和求解的效果,可以分为以下几种算法。

1. 贪心算法贪心算法是一种简单而有效的算法,它根据每个货物的优先级选择最佳的放置位置。

该算法通过贪心策略,逐步选择最佳装载位置,直到将所有货物装载完毕。

然而,贪心算法可能无法找到最优解,因为它只考虑当前局部最优解。

2. 动态规划算法动态规划算法是解决最优化问题的一种常用方法。

在航空货运装载问题中,可以通过动态规划算法来计算每个装载单元的最优解,并逐步求解整个装载问题。

然而,由于航空货运装载问题的复杂性,动态规划算法的时间复杂度会随着问题规模的增加而增加。

3. 遗传算法遗传算法是一种模拟生物进化过程的优化算法。

遗传算法解决装载问题的例子

遗传算法解决装载问题的例子

遗传算法解决装载问题的例子遗传算法是一种优化算法,它模拟自然选择和遗传机制,寻找最优解决方案。

装载问题是指如何最有效地将多个物体装载到一个限定容积的容器中。

本文将介绍遗传算法如何应用于解决装载问题的例子。

首先,我们需要定义问题的目标函数。

在装载问题中,我们希望最小化剩余容量,即最大化已装载物品的总体积。

因此,我们的目标函数可以定义为:f(x) = - (V - ∑vi)其中,f(x)表示染色体x的适应度,V表示容器的容积,vi表示第i个物品的体积。

接下来,我们需要定义染色体的编码方式。

在装载问题中,一种常用的编码方式是二进制编码。

假设我们有n个物品需要装载,我们可以将染色体编码为长度为n的二进制串,其中1表示对应物品被装载,0表示未被装载。

例如,对于四个物品,染色体0101表示第1和第3个物品被装载,第2和第4个物品未被装载。

然后,我们需要定义遗传算法的操作。

遗传算法通常包括选择、交叉和变异三种基本操作。

在装载问题中,我们可以采用轮盘赌选择操作,即根据染色体适应度进行选择。

交叉操作可以采用单点交叉或多点交叉,用于产生新的染色体。

变异操作可以随机翻转某一位二进制数,用于增加染色体的多样性。

最后,我们可以应用遗传算法进行求解。

假设我们有一个装载容器,其容积为100,同时有n个物品需要装载,每个物品的体积随机分布在[1,20]之间。

我们可以先随机生成一组初始染色体,然后进行遗传算法的迭代过程,直到找到最优解。

通过这样的方法,我们可以在较短的时间内找到最优的装载方案,解决装载问题。

此外,遗传算法还可以应用于其他优化问题的求解,具有广泛的应用前景。

航空货运装载问题算法设计与研究

航空货运装载问题算法设计与研究

航空货运装载问题算法设计与研究一、引言航空货运业是现代经济中不可或缺的一部分,它承载着跨国贸易、物流运输等重要任务。

但是,航空货运装载问题一直是困扰航空业的一个难题。

如何在有限的装载空间中,合理、高效地装载货物,不仅关系到货物的安全和完整性,还关系到航空公司的运营成本和效益。

对航空货运装载问题进行算法设计与研究具有重大意义。

二、航空货运装载问题的背景和现状1. 航空货运装载问题的背景航空货物装载问题是指如何在给定的飞机货仓内,按照一定的装载规则和限制条件,合理排布和装载各种货物,以达到最优的装载效果。

2. 航空货运装载问题的现状目前,在航空货运业中,一般采用人工经验进行货物的装载,存在装载不均匀、装载效率低下等问题。

虽然国内外已经有许多学者对航空货运装载问题进行了研究,但仍然存在许多难点和挑战。

三、航空货运装载问题的算法设计1. 航空货运装载问题的目标在进行算法设计时,首先需要明确航空货运装载问题的目标。

主要包括最大化装载效率、保证货物的安全性和完整性、降低航空公司的运营成本等。

2. 航空货运装载问题的限制条件在进行算法设计时,需要考虑到各种限制条件,如货仓的实际空间大小、货物的种类和重量、货物的特殊要求等。

3. 航空货运装载问题的算法设计方法针对航空货运装载问题,可以采用启发式算法、遗传算法、禁忌搜索算法等进行设计和优化。

通过模拟货物装载的过程,不断调整和优化装载方案,以达到最优的装载效果。

四、航空货运装载问题的研究进展1. 目前的研究成果国内外许多学者对航空货运装载问题进行了研究,提出了许多有效的算法和方法。

这些研究成果在一定程度上解决了航空货运装载问题中的一些难点和挑战。

2. 待解决的问题和挑战尽管已经取得了一定的成果,但航空货运装载问题仍然存在装载效率不高、计算复杂度大等问题,需要进一步深入研究和探讨。

五、个人观点和总结航空货运装载问题的算法设计与研究,是一个复杂而又具有挑战性的课题。

在未来的研究中,可以结合物流信息技术、智能优化算法等手段,进一步提高货物装载的效率和质量。

算法中的最优装载问题

算法中的最优装载问题

算法中的最优装载问题问题描述有n个集装箱要装上1艘载重量分别为c的轮船,其中第i个集装箱的重量为wi。

最优装载问题要求确定在装载体积不受限制的情况下,将尽可能多的集装箱装上轮船,并找出一种装载方案其中@w #集装箱的重量数组@c #货船的最大载重量@n #集装箱的个数@r #未被装载的货物重量@cw #当前货船上的载重@i #搜索树的层数@bestw #最优值@bestx #最优解class Loadingdef initialize(weight,cont)@w,@c,@n=weight,cont,weight.length@r,@cw,@i,@bestw=0,0,0,0@x=Array.new@bestx=Array.newfor j in 0..@n-1@r=@r+@w[j];@bestx[j],@x[j]=0,0endprint \\"集装箱的总重量为 #@r,\\n\\"enddef MaxLoadingwhile truewhile @i<=(@n-1) and (@cw+@w[@i]<@c)@r-=@w[@i]@cw+=@w[@i]@x[@i]=1print \\"在左子树中\\",@x[@i],\\"\\n\\"@i+=1endif @i>@n-1for j in 0..@n-1@bestx[j]=@x[@i]print \'到达叶子节点\',j,\\"\\t @bestx[j]\\",@bestx[j],\\"\\n\\" end@bestw=@cwelse@r-=@w[@i];@x[@i]=0;print \'在右子树中\',@x[@i],\\"\\n\\" @i+=1endwhile @cw+@r<=@bestw@i-=1while @i>=0 and (@x[@i]==0)@r+=@w[@i];@i-=1endif @i==-1 thenprint \\"@bestw:\\",@bestwreturnend@x[@i]=0@cw-=@w[@i]@i+=1endendendendweight=[30,10,10]cont=35s=Loading.new(weight,cont)s.MaxLoading运行的结果如下:集装箱的总重量为 50,在左子树中1在右子树中0在右子树中0到达叶子节点0 @bestx[j]nil到达叶子节点1 @bestx[j]nil到达叶子节点2 @bestx[j]nil@bestw:30>Exit code: 0。

算法——分支限界法(装载问题)

算法——分⽀限界法(装载问题)对⽐回溯法回溯法的求解⽬标是找出解空间中满⾜约束条件的所有解,想必之下,分⽀限界法的求解⽬标则是找出满⾜约束条件的⼀个解,或是满⾜约束条件的解中找出使某⼀⽬标函数值达到极⼤或极⼩的解,即在某种意义下的最优解。

另外还有⼀个⾮常⼤的不同点就是,回溯法以深度优先的⽅式搜索解空间,⽽分⽀界限法则以⼴度优先的⽅式或以最⼩耗费优先的⽅式搜索解空间。

分⽀限界法的搜索策略在当前节点(扩展节点)处,先⽣成其所有的⼉⼦节点(分⽀),然后再从当前的活节点(当前节点的⼦节点)表中选择下⼀个扩展节点。

为了有效地选择下⼀个扩展节点,加速搜索的进程,在每⼀个活节点处,计算⼀个函数值(限界),并根据函数值,从当前活节点表中选择⼀个最有利的节点作为扩展节点,使搜索朝着解空间上有最优解的分⽀推进,以便尽快地找出⼀个最优解。

分⽀限界法解决了⼤量离散最优化的问题。

选择⽅法1.队列式(FIFO)分⽀限界法队列式分⽀限界法将活节点表组织成⼀个队列,并将队列的先进先出原则选取下⼀个节点为当前扩展节点。

2.优先队列式分⽀限界法优先队列式分⽀限界法将活节点表组织成⼀个优先队列,并将优先队列中规定的节点优先级选取优先级最⾼的下⼀个节点成为当前扩展节点。

如果选择这种选择⽅式,往往将数据排成最⼤堆或者最⼩堆来实现。

例⼦:装载问题有⼀批共n个集装箱要装上2艘载重量分别为c1,c2的轮船,其中集装箱i的重量为wi,且要求确定是否有⼀个合理的装载⽅案可将这n个集装箱装上这2艘轮船。

可证明,采⽤如下策略可以得到⼀个最优装载⽅案:先尽可能的将第⼀艘船装满,其次将剩余的集装箱装到第⼆艘船上。

代码如下://分⽀限界法解装载问题//⼦函数,将当前活节点加⼊队列template<class Type>void EnQueue(Queue<Type> &Q, Type wt, Type &bestw, int i, int n){if(i == n) //可⾏叶结点{if(wt>bestw) bestw = wt ;}else Q.Add(wt) ; //⾮叶结点}//装载问题先尽量将第⼀艘船装满//队列式分⽀限界法,返回最优载重量template<class Type>Type MaxLoading(Type w[],Type c,int n){//初始化数据Queue<Type> Q; //保存活节点的队列Q.Add(-1); //-1的标志是标识分层int i=1; //i表⽰当前扩展节点所在的层数Type Ew=0; //Ew表⽰当前扩展节点的重量Type bestw=0; //bestw表⽰当前最优载重量//搜索⼦集空间树while(true){if(Ew+w[i]<=c) //检查左⼉⼦EnQueue(Q,Ew+w[i],bestw,i,n); //将左⼉⼦添加到队列//将右⼉⼦添加到队列即表⽰不将当前货物装载在第⼀艘船EnQueue(Q,Ew,bestw,i,n);Q.Delete(Ew); //取下⼀个节点为扩展节点并将重量保存在Ewif(Ew==-1) //检查是否到了同层结束{if(Q.IsEmpty()) return bestw; //遍历完毕,返回最优值Q.Add(-1); //添加分层标志Q.Delete(Ew); //删除分层标志,进⼊下⼀层i++;}}}算法MaxLoading的计算时间和空间复杂度为O(2^n).上述算法可以改进,设r为剩余集装箱的重量,当Ew+r<=bestw的时候,可以将右⼦树剪去。

贪心算法之最优装载问题

贪⼼算法之最优装载问题贪⼼算法之最优装载问题1. 问题描述有⼀批集装箱要装上⼀艘重量为c的轮船,其中集装箱i的重量为W i。

最优装载问题要求确定在装载体积不受限制的情况下,将尽可能多的集装箱装上轮船。

2. 问题分析2.1确定贪⼼策略采⽤重量最轻者先装的贪⼼选择策略,可产⽣该问题的最优解。

2.2代码求解/*** x[] 保存最优解路径数组* w[] 集装箱重量数组* c 船的载重量* n 集装箱的数量**/void Loading(int x[], int w[], int c, int n) {// 按照集装箱重量从⼩到⼤排序sort(w, n);for (int i = 1; i <= n; i++)x[i] = 0;for (int i = 1; i <= n && w[i] <= c; i++) {x[i] = 1;c -= w[i];}}2.3贪⼼选择性质设集装箱依其重量从⼩到⼤排序,(x1,x2,…,x n)是其最优解,x i={0,1},设x k是第⼀个等于1的。

(1) 如k=1,则满⾜贪⼼选择性质(2) 如k≠1,⽤x1替换x k,构造的新解同原解最优值相同,故也是最优解,满⾜贪⼼选择性质该证明⽅法只证明了任何⼀个最优解都可以转换为第⼀个集装箱上船的最优解(满⾜贪⼼策略)。

此⽅法对⼦问题同样有效,因此可以将⼀个普通最优解转化为满⾜贪⼼策略的最优解。

如(0101)⇒(1100)2.4.最优⼦结构性质最优装载问题具有最优⼦结构性质,设1⾄n个集装箱装上船的最⼤数量为T(1,n,w),则T(1,n,w)=1+T(2,n,w−w1);因T(1,n,w)是最优值,则T(2,n,w−w i)⼀定是最优值,反证法证明之反证法:如果T(2,n,w−w1)不是该问题的最优解,则存在最优值T′(2,n,w−w1)>T(2,n,w−w1),则1+T′(2,n,w−w1)=T′(1,n,w)>T(1,n,w),这与⼤前提T(1,n,w)是最优值相⽭盾,故T(2,n,w−w1)⼀定是最优值。

装载问题5种解决方案设计

算法分析与设计2016/2017(2)实验题目装载问题5种解法学生学生学号学生班级任课教师提交日期2017计算机科学与技术学目录一问题定义 (3)二解决方案 (3)1优先队列式分支限界法求解 (3)1.1算法分析 (3)1.2代码 (3)1.3运行结果 (13)2队列式分支限界法求解 (13)2.1算法分析 (13)2.2代码 (14)2.3测试截图 (22)3回朔法-迭代 (22)3.1算法分析 (22)3.2代码 (22)3.3测试截图 (26)4回朔法-递归 (26)4.1算法分析 (26)4.2代码 (27)4.3测试截图 (31)5贪心算法 (31)5.1算法分析 (31)5.2代码 (31)5.3测试截图 (35)一问题定义有一批共有 n 个集装箱要装上两艘载重量分别为 c1 和 c2 的轮船,其中集装箱 i 的重量为 w[i], 且重量之和小于(c1 + c2)。

装载问题要求确定是否存在一个合理的装载方案可将这 n 个集装箱装上这两艘轮船。

如果有,找出一种装载方案。

二解决方案1优先队列式分支限界法求解1.1算法分析活结点x在优先队列中的优先级定义为从根结点到结点x的路径所相应的载重量再加上剩余集装箱的重量之和。

优先队列中优先级最大的活结点成为下一个扩展结点。

以结点x为根的子树中所有结点相应的路径的载重量不超过它的优先级。

子集树中叶结点所相应的载重量与其优先级相同。

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

此时可终止算法。

1.2代码1.2-1////MaxHeap.htemplate<class T>class MaxHeap{public:MaxHeap(int MaxHeapSize = 10);~MaxHeap() {delete [] heap;}int Size() const {return CurrentSize;}T Max(){ //查找if (CurrentSize == 0){throw OutOfBounds();}return heap[1];}MaxHeap<T>& Insert(const T& x); //增MaxHeap<T>& DeleteMax(T& x); //删void Initialize(T a[], int size, int ArraySize);private:int CurrentSize, MaxSize;T *heap; // element array};template<class T>MaxHeap<T>::MaxHeap(int MaxHeapSize){// Max heap constructor.MaxSize = MaxHeapSize;heap = new T[MaxSize+1];CurrentSize = 0;}template<class T>MaxHeap<T>& MaxHeap<T>::Insert(const T& x){// Insert x into the max heap.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<class T>MaxHeap<T>& MaxHeap<T>::DeleteMax(T& x){// Set x to max element and delete max element from heap.// check if heap is emptyif (CurrentSize == 0){cout<<"Empty heap!"<<endl;return *this;}x = heap[1]; // 删除最大元素// 重整堆T y = heap[CurrentSize--]; // 取最后一个节点,从根开始重整// find place for y starting at rootint i = 1, // current node of heapci = 2; // child of iwhile (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;return *this;}template<class T>void MaxHeap<T>::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 yint c = 2*i; // parent of c is target// location for ywhile (c <= CurrentSize){// heap[c] should be larger siblingif (c < CurrentSize && heap[c] < heap[c+1]){c++;}// can we put y in heap[c/2]?if (y >= heap[c]){break; // yes}// noheap[c/2] = heap[c]; // move child upc *= 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{template<class Type>friend void AddLiveNode(MaxHeap<HeapNode<Type>>& H,bbnode *E,Type wt,bool ch,int lev);template<class Type>friend Type MaxLoading(Type w[],Type c,int n,int bestx[]);public:operator Type() const{return uweight;}private:bbnode *ptr; //指向活节点在子集树中相应节点的指针Type uweight; //活节点优先级(上界)int level; //活节点在子集树中所处的层序号};class bbnode{template<class Type>friend void AddLiveNode(MaxHeap<HeapNode<Type>>& H,bbnode *E,Type wt,bool ch,int lev);template<class Type>friend Type MaxLoading(Type w[],Type c,int n,int bestx[]);friend class AdjacencyGraph;private:bbnode *parent; //指向父节点的指针bool LChild; //左儿子节点标识};template<class Type>void AddLiveNode(MaxHeap<HeapNode<Type>>& H,bbnode *E,Type wt,bool ch,int lev);template<class Type>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<<"轮船载重为:"<<c<<endl;cout<<"待装物品的重量分别为:"<<endl;for(int i=1; i<=N; i++){cout<<w[i]<<" ";}cout<<endl;bestw = MaxLoading(w,c,N,x);cout<<"分支限界选择结果为:"<<endl;for(int i=1; i<=4; i++){cout<<x[i]<<" ";}cout<<endl;cout<<"最优装载重量为:"<<bestw<<endl;return 0;}//将活节点加入到表示活节点优先队列的最大堆H中template<class Type>void AddLiveNode(MaxHeap<HeapNode<Type>>& H,bbnode *E,Type wt,bool ch,intlev){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[]) {//定义最大的容量为1000MaxHeap<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];}//初始化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;}return Ew;}1.3运行结果2队列式分支限界法求解2.1算法分析在算法的循环体中,首先检测当前扩展结点的左儿子结点是否为可行结点。

回溯算法装载问题

实验六 回溯算法〔2学时〕一、实验目的与要求1、掌握装载问题的回溯算法;2、初步掌握回溯算法;二、实验题有一批共n 个集装箱要装上2艘载重量分别为c1和c2的轮船,其中集装箱i 的重量为wi ,且 装载问题要求确定是否有一个合理的装载方案可将这个集装箱装上这2艘轮船。

如果有,找出一种装载方案。

三、实验提示void backtrack (int i){// 搜索第i 层结点if (i > n) // 到达叶结点更新最优解bestx,bestw;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); }r += w[i];}四、实验代码方法1:import java.util.*;/*** 回溯法解决装载问题* author Administrator**/public class demo {public static int n; //集装箱数public static int first_weight; //第一艘载重量public static int beautif_weight; //当前最优载重量public static int[] arr_weight; //集装箱重量数组public static int[] **; //public static int[] best**;public static int maxLoadingRE(int[] w, int c, int[] bestx) {//递归回溯 n = w.length;first_weight = c;beautif_weight = 0;211c c w n i i +≤∑=arr_weight = w;best** = bestx;** = new int[n];int r = 0; //剩余集装箱重量,未进展装载的重量for (int i = 0; i < n; i++) {r += arr_weight[i];}trackback(0, 0, r);return beautif_weight;}//到达层数,目前装载的重量,未装载的重量private static void trackback(int i, int cw, int r) {if (i == n) {//到达叶结点for (int j = 0; j < n; j++) {best**[j] = **[j];}beautif_weight = cw;return; //只是一次出栈操作,栈非空还要继续执行}if (cw + arr_weight[i] <= first_weight) { //已装载的加上要装载的小于第一个的载重量**[i] = 0; //0代表装在第一个上,1代表装在第二个上trackback(i + 1, cw + arr_weight[i], r); //试图装载下一个集装箱,r是针对第一个装的重量,因此装在第一个里不需要减,但装在第二个时就要减去该重量}if (r - arr_weight[i] > beautif_weight) { //已装载的加上要装载的已经大于第一个的载重量,并且用总的载重量r减去当前要装载的还比最好的载重量大**[i] = 1; //放到第二个上trackback(i + 1, cw, r - arr_weight[i]);}}public static int maxLoading(int[] w, int c, int[] bestx) {int i = 0; //当前层int n = w.length; //层总数int[] x = new int[n]; //x[0, i]为当前选择路径Arrays.fill(x, -1); //初始化为-1,0表示选择第一个,1表示选择第二个int bestw = 0; //当前最优装载重量int[] cw = new int[n]; //当前载重量int[] r = new int[n]; //剩余集装箱容量int tor = 0;for (int item : w) {//item取出w中的值,进展相加tor += item;}r[0] = tor;//要装载的重量cw[0] = 0;//搜索子树while (i > -1) {do {x[i] += 1;if (x[i] == 0) { //选择放在第一个〔左子树〕if (cw[i] + w[i] <= c) {if (i < n - 1) {cw[i + 1] = cw[i] + w[i];r[i + 1] = r[i];}break; //能放下就直接跳出这个do-while循环}}else { //选择放在第二个〔右子树〕if (r[i] - w[i] > bestw) {//剪枝函数,没有最优解好的话x[i]会自增到2,不会进入下面的if (x[i] < 2)if (i < n - 1) {r[i + 1] = r[i] - w[i];cw[i + 1] = cw[i];}break;}}} while (x[i] < 2); //对于放不下的在这里判断后才能取右子树if (x[i] < 2) {if (i == n - 1) {for (int j = 0; j < n; j++) {bestx[j] = x[j];}if (x[i] == 0) {bestw = cw[i] + w[i];}else {bestw = cw[i];}}else {i++;x[i] = -1;}}else {//当x[i]=2时,说明已经遍历完两个叶节点,应向上一层继续遍历其它节点i--;}}return bestw;}public static void main(String[] args) {int[] w = {0,10,40,40};int n = w.length;int c = 50;int[] bestx = new int[n];System.out.println("重量分别为:");for(int ws:w){System.out.print(","+ws);}System.out.println("\n");int bestw = maxLoadingRE(w, c, bestx);System.out.println("回溯选择结果为: " + bestw); System.out.println(Arrays.toString(bestx));}}方法2:public class demo2 {public static void main(String[] args) {int n=3,m;int c=50,c2=50;int w[]={0,10,40,40};int bestx[]=new int[w.length];demo2 demo2=new demo2();m=demo2.MaxLoading(w, c, n, bestx);System.out.println("轮船的载重量分别为:");System.out.println("c(1)="+c+",c(2)="+c2);System.out.println("待装集装箱重量分别为:");System.out.print("w(i)=");for (int i=0;i<=n;i++){System.out.print(","+w[i]);}System.out.println(");System.out.println("最优装载量为:");System.out.println("m(1)="+m);System.out.print("x(i)=");for (int i=0;i<=n;i++){System.out.print("+bestx[i]);}System.out.println(");int m2=0;for (int j=1;j<=n;j++){m2=m2+w[j]*(1-bestx[j]);}System.out.println("回溯选择结果为:"+m2);if(m2>c2){System.out.println("因为m(2)大于c(2),所以原问题无解!");}}int MaxLoading(int w[],int c,int n,int bestx[])//迭代回溯法,返回最优载重量及其相应解,初始化根结点{int i=1;//当前层,x[1:i-1]为当前路径int x[]=new int[n+1];int bestw=0; //当前最优载重量int cw=0; //当前载重量int r=0; //剩余集装箱重量for (int j=1;j<=n;j++){r+=w[j];}while(true)//搜索子树{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){r+=w[i];i--;}//从右子树返回if (i==0){return bestw;}x[i]=0;cw-=w[i];i++;}}}}五、实验结果六、实验总结。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
相关文档
最新文档