0028算法笔记——【回溯法】批作业调度问题和符号三角形问题

合集下载

算法设计与分析——批处理作业调度(回溯法)

算法设计与分析——批处理作业调度(回溯法)

算法设计与分析——批处理作业调度(回溯法)之前讲过⼀个相似的问题流⽔作业调度问题,那⼀道题最开始⽤动态规划,推到最后得到了⼀个Johnson法则,变成了⼀个排序问题,有兴趣的可以看⼀下本篇博客主要参考⾃⼀、问题描述给定n个作业的集合{J1,J2,…,Jn}。

每个作业必须先由机器1处理,然后由机器2处理。

作业Ji需要机器j的处理时间为t ji。

对于⼀个确定的作业调度,设Fji是作业i在机器j上完成处理的时间。

所有作业在机器2上完成处理的时间和称为该作业调度的完成时间和。

批处理作业调度问题要求对于给定的n个作业,制定最佳作业调度⽅案,使其完成时间和达到最⼩。

例:设n=3,考虑以下实例:看到这⾥可能会对这些完成时间和是怎么计算出来的会有疑问,这⾥我拿123和312的⽅案来说明⼀下。

对于调度⽅案(1,2,3)作业1在机器1上完成的时间是2,在机器2上完成的时间是3作业2在机器1上完成的时间是5,在机器2上完成的时间是6作业3在机器1上完成的时间是7,在机器2上完成的时间是10所以,作业调度的完成时间和= 3 + 6 + 10这⾥我们可以思考⼀下作业i在机器2上完成的时间应该怎么去求?作业i在机器1上完成的时间是连续的,所以是直接累加就可以。

但对于机器2就会产⽣两种情况,这两种情况其实就是上图的两种情况,对于(1,2,3)的调度⽅案,在求作业2在机器2上完成的时间时,由于作业2在机器1上还没有完成,这就需要先等待机器1处理完;⽽对于(3,1,2)的调度⽅案,在求作业2在机器2上完成的时间时,作业2在机器1早已完成,⽆需等待,直接在作业1被机器1处理之后就能接着被处理。

综上,我们可以得到如下表达式if(F2[i-1] > F1[i])F2[i] = F2[i-1] + t[2][i]elseF2[i] = F1[i] + t[2][i]⼆、算法设计类Flowshop的数据成员记录解空间的结点信息,M输⼊作业时间,bestf记录当前最⼩完成时间和,数组bestx记录相应的当前最佳作业调度。

有期限的作业调度算法doc

有期限的作业调度算法doc

有期限的作业调度算法一、典型算法贪心算法是以局部最优为原则,通过一系列选择来得到问题的一个最优解,它所做的每一个选择都是当前状态下某种意义上的最佳选择.贪心算法适合于解决这样的问题:局部的最优解能够导致最终结果的最优解。

“有限期作业安排问题”描述如下:有n个任务每个任务Ji都有一个完成期限di,若任务Ji在它的期限di内完成,则可以获利Ci(l[i[n);问如何安排使得总的收益最大(假设完成每一个任务所需时间均为一个单位时间).这个问题适合用贪心算法来解决,贪心算法的出发点是每一次都选择利润大的任务来完成以期得到最多的收益;但是对于本问题由于每一个任务都有一个完成的期限因此在任务安排过程中除了考虑利润Ci外,还要考虑期限di.(一)算法描述1.假设用数组J存储任务,用数组C存储利润,用数组d存储期限,用数组P存储安排好的任务.按照利润从大到小的次序,调整任务的次序:对n个任务J1,J2,...,Jn进行调整,使其满足C1三C2三…三Cn.2.将排序后的任务顺次插入输出数组P.A)任务J[1]排在P[1];B)若已经优先安排了k个任务,则它们满足d[P[i]]三i(1WiWk),即利润较高的k个任务能够在它们的期限内完成•那么,对于第k+1个任务J[k+1],显然C[k+1]WC[i](1WiWk);比较d[k+1]和d[P[k]]:a)若d[k+1]大于d[P[k]],那么将它排在第k+1位(P[k+1]T[k+1]);b)若d[k+1]小于等于d[P[k]],那么,J[k]能否插入,需比较k和d[P[k]]而定:i)若k等于d[P[k]](其第k个任务已经排在可以满足的最迟时间),那么,因为Ck^Ck+1,只好放弃任务J[k+1];ii)若k小于d[P[k]](表示第k个任务还有推后的余地):若d[k+1]=k,将第k个任务后移一位(P[k+1]-P[k]),将第k+1个任务排在第k位(P[k]一J[k+1]).若d[k+1]<k,则继续比较任务J[k+1]与第k-1个任务,方法同上.C)重复B)直至处理完最后一个任务.3)输出P.(二)算法实现voidjob-arrangement(char*J[],intd[],intC[],intP[],intn){sort(C,J,d,n);/*按照降序调整数组C,同时对数组J!d作相应调整*/P[0]=0;d[0]=0;P[1]=1;k=1;for(i=2;i<=n;i++){r=k;while{(d[P[r]]>=d[i])&&d[P[r]]!=r}r--;if(d[P[r]]<d[i])for(h=k;h>r;h--)P[h+1]=P[h];k++;P[r+1]=i;}output(P,J,n)}(三)算法分析该算法在最坏情况下的时间复杂度是0(n?),在最好情况下的是0(n)二.利用UNION与FIND进行作业排序利用不相交集合的UNION与FIND算法以及使用一个不同的方法来确定部分解的可行性。

0018算法笔记——【动态规划】流水作业调度问题与Johnson法则

0018算法笔记——【动态规划】流水作业调度问题与Johnson法则

1、问题描述:n个作业{1,2,…,n}要在由2台机器M1和M2组成的流水线上完成加工。

每个作业加工的顺序都是先在M1上加工,然后在M2上加工。

M1和M2加工作业i所需的时间分别为ai和bi。

流水作业调度问题要求确定这n个作业的最优加工顺序,使得从第一个作业在机器M1上开始加工,到最后一个作业在机器M2上加工完成所需的时间最少。

2、问题分析直观上,一个最优调度应使机器M1没有空闲时间,且机器M2的空闲时间最少。

在一般情况下,机器M2上会有机器空闲和作业积压2种情况。

设全部作业的集合为N={1,2,…,n}。

S是N的作业子集。

在一般情况下,机器M1开始加工S中作业时,机器M2还在加工其他作业,要等时间t后才可利用。

将这种情况下完成S中作业所需的最短时间记为T(S,t)。

流水作业调度问题的最优值为T(N,0)。

设π是所给n个流水作业的一个最优调度,它所需的加工时间为aπ(1)+T’。

其中T’是在机器M2的等待时间为bπ(1)时,安排作业π(2),…,π(n)所需的时间。

记S=N-{π(1)},则有T’=T(S,bπ(1))。

证明:事实上,由T的定义知T’>=T(S,bπ(1))。

若T’>T(S,bπ(1)),设π’是作业集S在机器M2的等待时间为bπ(1)情况下的一个最优调度。

则π(1),π'(2),…,π'(n)是N的一个调度,且该调度所需的时间为aπ(1)+T(S,bπ(1))<aπ(1)+T’。

这与π是N的最优调度矛盾。

故T’<=T(S,bπ(1))。

从而T’=T(S,bπ(1))。

这就证明了流水作业调度问题具有最优子结构的性质。

由流水作业调度问题的最优子结构性质可知:从公式(1)可以看出,该问题类似一个排列问题,求N个作业的最优调度问题,利用其子结构性质,对集合中的每一个作业进行试调度,在所有的试调度中,取其中加工时间最短的作业做为选择方案。

将问题规模缩小。

批处理作业调度 回溯法

批处理作业调度  回溯法

批处理作业调度问题描述:N个作业要在两台机器上处理,每个作业必须先由机器1处理,然后再由机器2处理,机器1处理作业i所需时间为ai,机器2处理作业i所需时间为bi,批处理作业调度问题要求确定这n个作业的最优处理顺序,使得到处理结束所需的时间和最少。

输入:输出:最节省时间为25 应对方案为 1 3 2算法描述:回溯法按深度优先策略搜索问题的解空间树。

首先从根节点出发搜索解空间树,当算法搜索至解空间树的某一节点时,先利用剪枝函数判断该节点是否可行(即能得到问题的解)。

如果不可行,则跳过对该节点为根的子树的搜索,逐层向其祖先节点回溯;否则,进入该子树,继续按深度优先策略搜索。

回溯法的基本行为是搜索,搜索过程使用剪枝函数来为了避免无效的搜索。

剪枝函数包括两类:1. 使用约束函数,剪去不满足约束条件的路径;2.使用限界函数,剪去不能得到最优解的路径。

问题的关键在于如何定义问题的解空间,转化成树(即解空间树)。

解空间树分为两种:子集树和排列树。

两种在算法结构和思路上大体相同。

算法设计:设数组a[n]存储n个作业在机器1上的处理时间,数组b[n]存储n个作业在机器2上的处理时间。

数组x[n]存储具体的作业调度,初始迭代时x[0]表示未安排作业,x[k]表示第k个作业的编号。

数组sum1[n]存储机器1的完成时间,sum2[n]存储机器2的完成时间,初始迭代时sum1[0]和sum2[0]均为0,表示完成时间均为0,sum1[k]表示在安排第k个作业后机器1的当前完成时间,sum2[k]表示在安排第k个作业后机器2的当前完成时间举例:有三个作业1, 2, 3,这三个作业在机器1上所需的处理时间为(2, 5, 4),在机器2上所需的处理时间为(3, 2, 1),确定这n个作业的最优处理顺序,使得到处理结束所需的时间和最少。

确定这3个作业的最优处理顺序,使得到处理结束所需的时间和最少。

由此可知,最优处理顺序为(1,2,3)和(2,1,3)最短完成时间为12#include <iostream>using namespace std;#define MAX 200int* x1;//作业Ji在机器1上的工作时间;int* x2;//作业Ji在机器2上的工作时间;int number=0;//作业的数目;int* xOrder;//作业顺序;int* bestOrder;//最优的作业顺序;int bestValue=MAX;//最优的时间;int xValue=0;//当前完成用的时间;int f1=0;//机器1完成的处理时间;int* f2;//第i阶段机器2完成的时间;void BackTrace(int k){if (k>number){for (int i=1;i<=number;i++){bestOrder[i]=xOrder[i];}bestValue=xValue;}{for (int i=k;i<=number;i++){f1+=x1[xOrder[i]];f2[k]=(f2[k-1]>f1?f2[k-1]:f1)+x2[xOrder[i]];xValue+=f2[k];swap(xOrder[i],xOrder[k]);if (xValue<bestValue){BackTrace(k+1);}swap(xOrder[i],xOrder[k]);xValue-=f2[k];f1-=x1[xOrder[i]];}}}int main(){int i;cout<<"请输入作业数目:";cin>>number;x1=new int[number+1];x2=new int[number+1];xOrder=new int[number+1];bestOrder=new int[number+1];f2=new int[number+1];x1[0]=0;x2[0]=0;xOrder[0]=0;bestOrder[0]=0;f2[0]=0;cout<<"请输入每个作业在机器1上所用的时间:"<<endl; for (int i=1;i<=number;i++){cout<<"第"<<i<<"个作业=";cin>>x1[i];}cout<<"请输入每个作业在机器2上所用的时间:"<<endl; for (i=1;i<=number;i++){cout<<"第"<<i<<"个作业=";cin>>x2[i];}for (i=1;i<=number;i++){xOrder[i]=i;}BackTrace(1);cout<<"最节省的时间为:"<<bestValue;cout<<endl;cout<<"对应的方案为:";for (i=1;i<=number;i++){cout<<bestOrder[i]<<" ";}System (“pause”);return 0;}。

计算复杂性之回溯法.

计算复杂性之回溯法.

回溯法2
摘要:排列回溯 应用于:汉密尔顿路径问题 和平皇后问题
排列
问题:生成n个不同数字的所有排列。 解决方案: 1.经过所有的长度为n的n元字符串,剪除所有的非排列。 2.设一个布尔数组U[1..n],如果m是未用的,U[m]是ture。 3.用一个数组A[1..n]来表示当前的排列。 4.目的是调用process(a),一旦A[1..n]包含当前排列。 调用程序permute(n): procedure permute(m) comment process all perms of length m 1. if m = 0 then process(A) else 2. for j := 1 to n do 这里和前面的汉密尔 3. if U[j] then 顿环问题是一样的。 4. U[j]:=false 一个汉密尔顿环就是 5. A[m] := j; permute(m− 1) 图像节点的一个排列。 6. U[j]:=true
ቤተ መጻሕፍቲ ባይዱ举搜索
穷举搜索,顾名思义,就是尝试所求问题的所有可能性。 穷举搜索的时间往往很慢,但也有一些关于标准的工具来帮 助我们使用:生成基本项目的算法,比如: 1.长度为n的二进制字符串共有2n个字符。 2.长度为n的k-ary字符串有kn个字符 3.n!种排列方式 4.在n样事物中选取r件事物,共有n!/r!(n-r)!种组合。 回溯法可以通过“优化修剪”的方法加速穷举搜索。
回溯基本问题1、位串问题
问题:生成含有n个字符的所有字符串。 解题思路:使用分治法。用数组A[1..n]来保存当前的二进制 字符串。目的是调用process(A)一次,用数组A[1..n]保存 每个二进制字符串。 伪代码: Procedure binary(m ) comment process all binary strings of length m if m =0 then process(A ) else A [m ]:=0;binary(m − 1) A [m ]:=1;binary(m − 1)

分支限界法-批处理调度问题

分支限界法-批处理调度问题

【分支限界法】批处理作业调度问题问题描述给定n个作业的集合J1,J2,…,J。

每个作业必须先由机器1处理,然后由机器2处理。

作业Ji需要机器j的处理时间为tji。

对于一个确定的作业调度,设Fji是作业i在机器j上完成处理的时间。

所有作业在机器2上完成处理的时间和称为该作业调度的完成时间和。

批处理作业调度问题要求对于给定的个作业,制定最佳作业调度方案,使其完成时间和达到最小例:设n=3,考虑以下实例:作业作业作业这3个作业的6种可能的调度方案是1,2,3;1,3,2;2,1,3;2,3,1;3,1,2;3,2,1;它们所相应的完成时间和分别是19,18, 20,21,19, 19。

易见,最佳调度方案是1,3,2,其完成时间和为18。

限界函数批处理作业调度问题要从n个作业的所有排列中找出具有最小完成时间和的作业调度,所以如图,批处理作业调度问题的解空间是一颗排在作业调度问相应的排列空间树中,每一个节点E都对应于一个已安排的作业集,……〈。

以该节点为根的子树中所含叶节点的完成时间和可表示为:设|M|=r,且L是以节点E为根的子树中的叶节点,相应的作业调度为{pk,k=1,2,……1其中pk是第k个安排的作业。

如果从节点E到叶节点L的路上,每一个作业pk在机器1上完成处理后都能立即在机器2上开始处理,即从p r+1开始,机器1没有空闲时间,则对于该叶节点L有:Z七=2 [耳心+(〃-左+1居网+%热]=d£叩+1i更M注:(n-k+1)tipk因为是完成时间和,所以,后续的n-k+1)个作业完成时间和都得算上ipk。

如果不能做到上面这一点,则si只会增加,从而有:下;, 一」。

类似地,如果从节点E开始到节点L的路上,从作业p r+1开始,机器2没有空闲时间,则:日25;E [max(勺,/+呻4) + ("4 + 1H热]k=r+l冈同理可知,s2是三;•的下界。

由此得到在节点E处相应子树中叶节点完成时间和的下界是:/吓 J+maxf3}ieM注意到如果选择Pk,使tipk在k>=r+1时依非减序排列,S1则取得极小值。

分支限界法解批处理作业调度问题java

分支限界法解批处理作业调度问题java

作业调度问题是指在多道程序系统中,根据各道程序的特点和系统的资源状况,合理地安排各道程序的执行顺序。

而分支限界法是一种解决排列、组合、0-1背包等问题的常用技术,可以有效地解决作业调度问题。

本文将结合Java语言,介绍如何使用分支限界法来解决作业调度问题。

一、作业调度问题的基本概念1. 作业调度问题的定义作业调度是指计算机系统对各种作业的安排和分配,以便使计算机系统有效地利用资源,提高各类作业的完成时间和各项资源的利用率。

2. 作业调度问题的类型作业调度问题主要分为单机调度和并行机调度两种类型。

其中单机调度是指一个作业在一台机器上进行处理,而并行机调度是指多个作业在多台机器上进行处理。

3. 作业调度问题的目标作业调度问题的主要目标是减少作业的等待时间,提高系统吞吐量,提高资源利用率,减少作业的周转时间等。

二、分支限界法的基本原理1. 分支限界法的概念分支限界法是一种剪枝技术,通过遍历搜索所有可能的解空间,并在搜索过程中剪掉某些明显不可能得到最优解的分支,从而有效地降低了搜索空间的规模。

2. 分支限界法的特点分支限界法在搜索过程中,通过剪枝操作,能够大大降低搜索空间的规模,提高搜索效率。

在解决NP难问题时,分支限界法通常能够得到较为满意的解。

3. 分支限界法的应用分支限界法被广泛应用于排列、组合、0-1背包、作业调度等各种组合优化问题的求解过程中,具有较高的实用性和效率。

三、分支限界法解决作业调度问题的具体步骤1. 确定问题的数学模型需要将作业调度问题转化为数学模型,例如采用Gantt图或者某种数学表达形式来描述作业的调度顺序和资源分配情况。

2. 设计合适的状态空间树根据问题的特点,设计合适的状态空间树来表示各种可能的作业调度方案,并利用分支限界法进行搜索。

3. 利用分支限界法进行搜索对设计好的状态空间树进行搜索,通过适当的剪枝操作,降低搜索空间的规模,提高搜索效率,直到找到最优解或者满意解为止。

作业调度问题.ppt

作业调度问题.ppt
j0
1 2 3 4 5 6 7 8 9 10 11 12 13 14
(f)14
a2
j2
j1
a0
j0
b0
b2
a1
b1
j2
a2 b2
a1 b1
j1
a0
b0
j0
1 2 3 4 5 6 7 8 9 10 11 12 13 14
1 2 3 4 5 6 7 8 9 10 11 12 13 14
a2 b2
j2
a1 b1
a3 b3
a2
b2
j2
a1
b1
j1
a0
j0
b0
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
j3
a2
j2
a3
b3
b2
a1
b1
j1
a0
j0
b0
a4 b4
j4
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
(a)12
(b)14
(c)13
j2
a1
j1
a0 b0
j0
a2 b2 b1
j2
a2
b2
j1 a1 b1
j0
a0 b0
1 2 3 4 5 6 7 8 9 10 11 12 13 14
(d)12
1 2 3 4 5 6 7 8 9 10 11 12 13 14
(e)15
a2 b2
j2
j1
a1
b1
a0 b0
j1
a0
b0
j0
1 2 3 4 5 6 7 8 9 10 11 12 13 14

0027算法笔记——【回溯法】回溯法与装载问题

0027算法笔记——【回溯法】回溯法与装载问题

1、回溯法(1)描述:回溯法是一种选优搜索法,按选优条件向前搜索,以达到目标。

但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法。

(2)原理:回溯法在问题的解空间树中,按深度优先策略,从根结点出发搜索解空间树。

算法搜索至解空间树的任意一点时,先判断该结点是否包含问题的解。

如果肯定不包含,则跳过对该结点为根的子树的搜索,逐层向其祖先结点回溯;否则,进入该子树,继续按深度优先策略搜索。

回溯法的基本做法是搜索,或是一种组织得井井有条的,能避免不必要搜索的穷举式搜索法。

这种方法适用于解一些组合数相当大的问题。

有许多问题,当需要找出它的解集或者要求回答什么解是满足某些约束条件的最佳解时,往往要使用回溯法。

(3)问题的解空间问题的解向量:回溯法希望一个问题的解能够表示成一个n元式(x1,x2,…,xn)的形式。

显约束:对分量xi的取值限定。

隐约束:为满足问题的解而对不同分量之间施加的约束。

解空间:对于问题的一个实例,解向量满足显式约束条件的所有多元组,构成了该实例的一个解空间。

注意:同一个问题可以有多种表示,有些表示方法更简单,所需表示的状态空间更小(存储量少,搜索方法简单)。

例1:n=3的0——1 背包问题的回溯法搜索过程。

W=[16,15,15] p=[45,25,25] C=30例2:旅行售货员问题。

某售货员要到若干城市去推销商品,已知各城市之间的路程(旅费),他要选定一条从驻地出发,经过每个城市一遍,最后回到驻地的路线,使总的路程(总旅费)最小。

(4)生成问题状态的基本方法扩展结点:一个正在产生儿子的结点称为扩展结点。

活结点:一个自身已生成但其儿子还没有全部生成的节点称做活结点。

死结点:一个所有儿子已经产生的结点称做死结点。

深度优先的问题状态生成法:如果对一个扩展结点R,一旦产生了它的一个儿子C,就把C当做新的扩展结点。

在完成对子树C(以C为根的子树)的穷尽搜索之后,将R重新变成扩展结点,继续生成R的下一个儿子(如果存在)。

0028算法笔记——【回溯法】批作业调度问题和符号三角形问题

0028算法笔记——【回溯法】批作业调度问题和符号三角形问题

1、批作业调度问题(1)问题描述给定n个作业的集合{J1,J2,…,Jn}。

每个作业必须先由机器1处理,然后由机器2处理。

作业Ji需要机器j的处理时间为tji。

对于一个确定的作业调度,设Fji是作业i在机器j上完成处理的时间。

所有作业在机器2上完成处理的时间和称为该作业调度的完成时间和。

批处理作业调度问题要求对于给定的n个作业,制定最佳作业调度方案,使其完成时间和达到最小。

例:设n=3,考虑以下实例:这3个作业的6种可能的调度方案是1,2,3;1,3,2;2,1,3;2,3,1;3,1,2;3,2,1;它们所相应的完成时间和分别是19,18,20,21,19,19。

易见,最佳调度方案是1,3,2,其完成时间和为18。

(2)算法设计批处理作业调度问题要从n个作业的所有排列中找出具有最小完成时间和的作业调度,所以如图,批处理作业调度问题的解空间是一颗排列树。

按照回溯法搜索排列树的算法框架,设开始时x=[1,2,……n]是所给的n个作业,则相应的排列树由x[1:n]的所有排列构成。

算法具体代码如下:[cpp]view plain copy1.#include "stdafx.h"2.#include <iostream>ing namespace std;4.5.class Flowshop6.{7.friend int Flow(int **M,int n,int bestx[]);8.private:9.void Backtrack(int i);10.11.int **M, // 各作业所需的处理时间12. *x, // 当前作业调度13. *bestx, // 当前最优作业调度14.15. *f2, // 机器2完成处理时间16. f1, // 机器1完成处理时间17. f, // 完成时间和18.19. bestf, // 当前最优值20. n; // 作业数21. };22.23.int Flow(int **M,int n,int bestx[]);24.25.template <class Type>26.inline void Swap(Type &a, Type &b);27.28.int main()29.{30.int n=3,bf;31.int M1[4][3]={{0,0,0},{0,2,1},{0,3,1},{0,2,3}};32.33.int **M=new int*[n+1];34.35.for(int i=0;i<=n;i++)36. {37. M[i]=new int[3];38. }39. cout<<"M(i,j)值如下:"<<endl;40.41.for(int i=0;i<=n;i++)42. {43.for(int j=0;j<3;j++)44. {45. M[i][j]=M1[i][j];46. }47. }48.49.int bestx[4];50.for(int i=1;i<=n;i++)51. {52. cout<<"(";53.for(int j=1;j<3;j++)54. cout<<M[i][j]<<" ";55. cout<<")";56. }57.58. bf=Flow(M,n,bestx);59.60.for(int i=0;i<=n;i++)61. {62.delete []M[i];63. }64.delete []M;65.66. M=0;67.68. cout<<endl<<"最优值是:"<<bf<<endl;69. cout<<"最优调度是:";70.71.for(int i=1;i<=n;i++)72. {73. cout<<bestx[i]<<" ";74. }75. cout<<endl;76.return 0;77.}78.79.void Flowshop::Backtrack(int i)80.{81.if (i>n)82. {83.for (int j=1; j<=n; j++)84. {85. bestx[j] = x[j];86. }87. bestf = f;88. }89.else90. {91.for (int j = i; j <= n; j++)92. {93. f1+=M[x[j]][1];94.//机器2执行的是机器1已完成的作业,所以是i-195. f2[i]=((f2[i-1]>f1)?f2[i-1]:f1)+M[x[j]][2];96.97. f+=f2[i];98.if (f < bestf)//剪枝99. {100. Swap(x[i], x[j]); 101. Backtrack(i+1); 102. Swap(x[i], x[j]); 103. }104. f1-=M[x[j]][1];105. f-=f2[i];106. }107. }108.}109.110.int Flow(int **M,int n,int bestx[]) 111.{112.int ub=30000;113.114. Flowshop X;115. X.n=n;116. X.x=new int[n+1];117. X.f2=new int[n+1];118.119. X.M=M;120. X.bestx=bestx;121. X.bestf=ub;122.123. X.f1=0;124. X.f=0;125.126.for(int i=0;i<=n;i++)127. {128. X.f2[i]=0,X.x[i]=i;129. }130. X.Backtrack(1);131.delete []X.x;132.delete []X.f2;133.return X.bestf;134.}135.136.template <class Type>137.inline void Swap(Type &a, Type &b) 138.{139. Type temp=a;140. a=b;141. b=temp;142.}由于算法Backtrack在每一个节点处耗费O(1)计算时间,故在最坏情况下,整个算法计算时间复杂性为O(n!)。

符号三角形问题

符号三角形问题

符号三角形问题计算机科学与技术一班徐启桂学号20044155591、思想:写出主函数,写出打印函数,根据书上给出的类,可以实现该问题对于符号三角行问题,用n元数组x[1:n]存放第一行的n个符号,用递归方法backtrack(i)实现对整个解空间的回溯搜索。

backtrack()搜索解空间第i层子树。

当i>n时,臬法搜索至叶结点,得到一个新的”+”个数与”-“的个数相同的符号三角形,当前已找到符号三角形数sum增加1.当i<n时,当前扩展结点Z是解空间中的内部结点。

该结点有x[i]=1和x[i]=0共两个儿子结点。

对当前扩展结点Z的每一个儿子结点,计算其相应的符号三角形中”+”个数count与”-“个数,并以深度优先的主式递归地对可行子树搜索,或剪去不可行子树。

//主函数:public static void main(String []args){System.out.println("要求解的符号三角形打印如下:\n");long sum = compute(3);//输入的个数为3;System.out.println("\n符合要求的符号三角形的个数共为:"+sum);}//打印函数:public static void printTriangles(){int m = n;// System.out.println(m--);for(int i = 1;i <= n;i++){for(int k = 1;k < i;k++)System.out.print(" ");for(int j = 1;j <= m;j++){if(p[i][j] == 1)System.out.print("+ ");else if(p[i][j] == 0)System.out.print("- ");}m--;System.out.println();}}/backtrack函数:private static void backtrack(int t){if((count>half)||(t*(t-1)/2-count>half)) return;//判断当前层+号和-号的个数是否满足约束条件if(t>n){sum++;printTriangles();}elsefor(int i=0;i<2;i++){ //三角形的第一层有两种可能性,分别考虑p[1][t]=i; //第一层放符号i,i=0,-号,i=1,+号count+=i; //统计+号的个数for(int j=2;j<=t;j++){p[j][t-j+1]=1-(p[j-1][t-j+1]^p[j-1][t-j+2]);count+=p[j][t-j+1];}backtrack(t+1);for(int j=2;j<=t;j++)count-=p[j][t-j+1];count-=i;}}算法分析:计算可行性约束需要o(n)时间,最坏情况下有2的n次方个结点需要计算,因此该回溯算法所需要的时间是o(n 2xN): 二的n次方。

符号三角形问题回溯法

符号三角形问题回溯法

符号三角形问题回溯法
符号三角形问题可以使用回溯法来解决。

回溯法在求解问题时,首先采取深度优先遍历,当发现当前搜索
的解不符合条件时,就返回上一步,回溯到上一个状态继续搜索。


种方法是一种暴力搜索的方法,但是当搜索错解时,可以避免无效的
搜索。

针对符号三角形问题,我们可以将问题转化为填充三角形,使得
每行的相邻两个数字之间的运算符的结果等于该行的最后一个数字。

我们可以从三角形的顶部开始填充,用一个列表来存储路径,每
次添加一个新的数字时,都会对路径进行检查,以确认当前状态是否
满足条件。

如果符合条件,则继续向下搜索,否则回溯到上一个状态。

如果找到了一个合法的解,就将它输出,并回溯到上一个状态,
搜索下一个可能的解。

需要注意的是,在回溯过程中,我们需要将已经访问过的节点进
行标记,避免重复访问。

通过回溯法求解符号三角形问题,可以快速地找到所有合法的解,但是需要遍历所有的可能解,因此时间复杂度较高。

算法设计与分析课件--回溯法-作业调度问题

算法设计与分析课件--回溯法-作业调度问题
❖ 计算任务由计算机的中央处理器完成,打印输出任务 由打印机完成。
❖ 计算机处理器是机器1,打印机是机器2。
5
5.4 作业调度问题
tmi 作业J1 作业J2 作业J3
机器m1 2 3 2
机器m2 1 1 3
调度一:1, 2, 3
F11=2 F21=3 F12=5 F22=5+1=6 F13=7 F23=7+3=10 f = F21+F22+F23 = 19
cf<bestf,限界条件满 K L
足,扩展生成的结点
J成为活结点。
24
5.4 作业调度问题
tmi 机器m1 机器m2
作业J1
2
1
作业J2
3
作业J3
2
1
A
3
x1=1 x1=2
B
C
x1=3 D
◼ 沿着结点 J 的x3=1 x2=2 x2=3 x2=1 x2=3 x2=1 x2=2
的分支扩展:
E
FG
H
//更新完成时间之和
if (f < bestf)
//判断与当前最优解之间的关系
Swap(x[i], x[j]);
//将j位置上的任务序号与i位置上的互换
backtrack(i+1);
//递归进行下一层的调度
Swap(x[i], x[j]);
//回溯,还原,执行第i层的下一个任务
f1 f1 - M[x[j]][1]; //出栈要回溯到父亲节点,先恢复数据;
K
L
❖此 时 , 找 到 比 先 前 更 优 的 一 种 调 度 方 案 (1,3,2) , 修 改 bestf=18 。
14

分支限界法求解批作业处理调度问题的实验总结(一)

分支限界法求解批作业处理调度问题的实验总结(一)

分支限界法求解批作业处理调度问题的实验总结(一)前言本文将介绍分支限界法在求解批作业处理调度问题中的实验结果,并总结这种方法在实践中的应用效果。

批作业处理调度问题是一个经典的优化问题,通过引入分支限界法求解,可以有效提高求解效率。

正文问题描述批作业处理调度问题是将一批作业分配给多台处理机,使得总完成时间最短。

每个作业有一个处理时间,各个处理机的处理速度可能不同,且每个处理机同时只能处理一项作业。

问题的目标就是找到一个合适的作业分配方案,使得总完成时间最小。

分支限界法原理分支限界法是一种优化算法,通过不断剪枝和界限约束,逐步地搜索最优解。

在批作业处理调度问题中,分支限界法的基本思想是将问题划分为子问题,并通过计算每个子问题的上界,动态地选择优先搜索的分支。

本次实验选取了一批作业和多台处理机,随机生成了作业的处理时间和处理机的处理速度。

利用分支限界法和贪心算法分别求解了批作业处理调度问题,并比较了两者的求解效果。

实验结果实验结果显示,分支限界法在求解批作业处理调度问题时表现出了较高的效率和准确性。

与贪心算法相比,分支限界法能够找到更优的作业分配方案,并且所需的计算时间相对较短。

实际应用分支限界法在实际生产中广泛应用于调度问题的求解。

无论是生产线的作业调度、机器设备的任务分配,还是人员的排班安排,都可以通过分支限界法来优化求解。

其高效的搜索方式和较好的求解结果使其成为一种实用的求解方案。

结尾通过本次实验,我们验证了分支限界法在求解批作业处理调度问题中的有效性。

分支限界法不仅能够在较短的时间内找到较优的解决方案,而且还可以应用于各种实际的调度问题。

希望通过本文的介绍,能够增加对分支限界法的了解和认识,并促进其在实际应用中的推广和应用。

为了求解批作业处理调度问题,我们使用了分支限界法和贪心算法两种方法进行对比。

首先,我们随机生成了一批作业和多台处理机。

每个作业的处理时间和每台处理机的处理速度也随机生成。

这样可以模拟实际情况中作业的不同耗时和处理机的不同处理能力。

批处理作业调度_分支限界法

批处理作业调度_分支限界法

批处理作业调度_分⽀限界法⼀、问题描述给定 n 个作业的集合 j = {j1, j2, …, jn}。

每⼀个作业 j[i] 都有两项任务分别在两台机器上完成。

每⼀个作业必须先由机器1 处理,然后由机器2处理。

作业 j[i] 需要机器 j 的处理时间为 t[j][i] ,其中i = 1, 2, …, n, j = 1, 2。

对于⼀个确定的作业调度,设F[j][i]是作业 i 在机器 j 上的完成处理的时间。

所有作业在机器2上完成处理的时间之和 f = sigma F[2][i] 称为该作业调度的完成时间之和。

批处理作业调度问题要求对于给定的 n 个作业,制定最佳作业调度⽅案,使其完成时间和达到最⼩。

⼆、解题思路及所选算法策略的可⾏性分析⽤优先队列式分⽀限界法解决此问题。

由于要从n个作业的所有排列中找出有最⼩完成时间和的作业调度,所以批处理作业调度问题的解空间树是⼀颗排列树。

对于批处理作业调度问题,可以证明存在最佳作业调度使得在机器1和机器2上作业以相同次序完成(因为每个作业必须先在机器1上完成作业才能在机器2上进⾏作业)。

如果对于未安排的作业,对于其中⼀个作业,每当该作业在机器1上完成处理后都能⽴即在机器2上开始处理,则机器1没有空闲时间,达到满⼯作状态,将此情况的未安排作业在机器2上的⼯作时间总和记为S1,同理将机器2满⼯作状态的情况下的⼯作时间总和记为S2,则必有:所有作业机器2上完⼯时间和 >= 已安排作业机器2上完⼯时间和 + max{S1,S2}其中当未安排作业按照在机器1、2上⼯作时间⾮递减顺序进⾏调度时,S1和S2同时取得极⼩值且和调度⽆关,由此可作为分⽀限界法中的限界函数。

伪代码描述及复杂度分析bbFlow(){对各作业在机器1和2上作旭时间排序do{if(到达叶结点){if(当前作业安排机器2上完成时间和 < bestc){更新bestc;更新最优解;}}else{For(int i=enode.已安排作业数; i<总作业数; i++){求得当前下届bb;If(bb < bestc){结点插⼊最⼩堆;}}}取下⼀个拓展结点;}while(enode!=null&&enode.s<=n)}三、代码实现package分⽀限界法;public class Nodes implements Comparable {int s;//已安排作业数int sf2;//当前机器2上的完成时间和int bb;//当前完成时间和下界int[] f;//f[1]机器1上最后完成时间,f[2]机器2上最后完成时间int[] x;//当前作业调度public Nodes(int n){//最⼩堆结点初始化x=new int[n];for(int i=0;i<n;i++)x[i]=i;s=0;f=new int[3];f[1]=0;f[2]=0;sf2=0;bb=0;}public Nodes(Nodes e,int[] ef,int ebb,int n){//最⼩堆新结点x=new int[n];for(int i=0;i<n;i++)x[i]=e.x[i];f=ef;sf2=e.sf2+f[2];bb=ebb;s=e.s+1;}@Overridepublic int compareTo(Object o) {int xbb=((Nodes) o).bb;if(bb<xbb) return -1;if(bb==xbb) return 0;return 1;}}public class BBFlow {public int n;//作业数public int bestc;//最⼩完成时间和public int [][]m;//n个作业所需的处理时间数组public int [][]b;//n个作业所需的处理时间排序数组public int[][] a;//数组m和b的对应关系数组public int[] bestx;//最优解public boolean[][] y;//⼯作数组public BBFlow(int n,int[][] m){this.n=n;bestc=10000;this.m=m;b=new int[n][2];a=new int[n][2];bestx=new int[n];y=new boolean[n][2];}public void swap(int[][] b,int i,int j,int k,int t){int temp=b[i][j];b[i][j]=b[k][t];b[k][t]=temp;}public void swap(int[] x,int i,int j){int temp=x[i];x[i]=x[j];x[j]=temp;}* 对n个作业在机器1和2上所需时间排序*/public void sort(){int[] c=new int[n];for(int j=0;j<2;j++){for(int i=0;i<n;i++){b[i][j]=m[i][j];c[i]=i;}for(int i=0;i<n-1;i++){for(int k=n-1;k>i;k--){if(b[k][j]<b[k-1][j]){swap(b,k,j,k-1,j);swap(c,k,k-1);}}}for(int i=0;i<n;i++)a[c[i]][j]=i;}}/*** 计算完成时间和下界* @param enode* @param f* @return*/public int bound(Nodes enode,int[] f){for(int k=0;k<n;k++){for(int j=0;j<2;j++){y[k][j]=false;}}for(int k=0;k<enode.s;k++){for(int j=0;j<2;j++){y[a[enode.x[k]][j]][j]=true;}}f[1]=enode.f[1]+m[enode.x[enode.s]][0];f[2]=((f[1]>enode.f[2])?f[1]:enode.f[2])+m[enode.x[enode.s]][1];int sf2=enode.sf2+f[2];int s1=0;int s2=0;int k1=n-enode.s;int k2=n-enode.s;int f3=f[2];//计算s1的值for(int j=0;j<n;j++){if(!y[j][0]){k1--;if(k1==n-enode.s-1)f3=(f[2]>f[1]+b[j][0])?f[2]:f[1]+b[j][0];s1+=f[1]+k1*b[j][0];}}//计算s2的值for(int j=0;j<n;j++){if(!y[j][1]){k2--;s1+=b[j][1];s2+=f3+k2*b[j][1];}//返回完成时间和下界return sf2+((s1>s2)?s1:s2);}/*** 优先队列式分⽀限界法解批处理作业调度问题* @param nn* @return*/public int bbFlow(int nn){n=nn;sort();//对n个作业在机器1和2上所需时间排序LinkedList<Nodes> heap=new LinkedList<Nodes>();Nodes enode =new Nodes(n);//搜索排列空间树do{if(enode.s==n){//叶节点if(enode.sf2<bestc){bestc=enode.sf2;for(int i=0;i<n;i++){bestx[i]=enode.x[i];}}}else{//产⽣当前扩展结点的⼉⼦结点for(int i=enode.s;i<n;i++){swap(enode.x,enode.s,i);int[] f=new int[3];int bb=bound(enode,f);if(bb<bestc){//⼦树可能含有最优解//结点插⼊最⼩堆Nodes node=new Nodes(enode,f,bb,n);heap.add(node);Collections.sort(heap);}swap(enode.x,enode.s,i);}//完成结点扩展}//取下⼀个扩展结点enode=heap.poll();}while(enode!=null&&enode.s<=n);return bestc;}public static void main(String[] args) {int n=3;int[][] m={{2,1},{3,1},{2,3}};//m的下标从0开始BBFlow f=new BBFlow(n,m);f.bbFlow(n);System.out.println("最优批处理作业调度顺序为:");for(int i=0;i<n;i++)System.out.print((f.bestx[i]+1)+" ");System.out.println();System.out.println("最优调度所需的最短时间为:"+f.bestc); }}/**************************运⾏结果*最优批处理作业调度顺序为:*1 3 2*最优调度所需的最短时间为:18 *************************/。

回溯法 符号三角形

回溯法 符号三角形

回溯法符号三角形
回溯法是一种求解约束满足问题的方法,符号三角形问题也是一种约束满足问题。

在符号三角形问题中,我们需要找到有多少种不同的符号三角形,使得其包含特定数量的“+”和“-”。

回溯法可以通过穷举所有可能的解来解决符号三角形问题。

具体来说,我们可以从第一行开始,不断改变每个符号,然后递归地搜索所有可能的解。

在搜索过程中,我们可以使用异或运算符来表示符号三角形中相邻两行之间的关系,并利用约束函数来排除不符合条件的解。

由于“+”和“-”的数目必须相等,因此我们可以将问题转化为求解异或树的问题。

在异或树中,每个节点表示一个符号,根节点表示第一行的符号,其他节点的值可以通过对其子节点的值进行异或运算得到。

在搜索过程中,我们可以利用异或树的性质来剪枝,排除不符合条件的分支。

通过回溯法,我们可以找到所有符合条件的符号三角形,并计算出它们的数量。

0018算法笔记__[动态规划]流水作业调度问题及Johnson法则

0018算法笔记__[动态规划]流水作业调度问题及Johnson法则

0018算法笔记——【动态规划】流水作业调度问题与Johnson 法则1、问题描述:n个作业{1,2,…,n}要在由2台机器M1和M2组成的流水线上完成加工。

每个作业加工的顺序都是先在M1上加工,然后在M2上加工。

M1和M2加工作业i所需的时间分别为ai和bi。

流水作业调度问题要求确定这n个作业的最优加工顺序,使得从第一个作业在机器M1上开始加工,到最后一个作业在机器M2上加工完成所需的时间最少。

2、问题分析直观上,一个最优调度应使机器M1没有空闲时间,且机器M2的空闲时间最少。

在一般情况下,机器M2上会有机器空闲和作业积压2种情况。

设全部作业的集合为N={1,2,…,n}。

S是N的作业子集。

在一般情况下,机器M1开始加工S中作业时,机器M2还在加工其他作业,要等时间t后才可利用。

将这种情况下完成S中作业所需的最短时间记为T(S,t)。

流水作业调度问题的最优值为T(N,0)。

设π是所给n个流水作业的一个最优调度,它所需的加工时间为aπ(1)+T’。

其中T’是在机器M2的等待时间为bπ(1)时,安排作业π(2),…,π(n)所需的时间。

记S=N-{π(1)},则有T’=T(S,bπ(1))。

证明:事实上,由T的定义知T’>=T(S,bπ(1))。

若T’>T(S,bπ(1)),设π’是作业集S在机器M2的等待时间为bπ(1)情况下的一个最优调度。

则π(1),π'(2),…,π'(n)是N的一个调度,且该调度所需的时间为aπ(1)+T(S,bπ(1))<aπ(1)+T’。

这与π是N的最优调度矛盾。

故T’<=T(S,bπ(1))。

从而T’=T(S,bπ(1))。

这就证明了流水作业调度问题具有最优子结构的性质。

由流水作业调度问题的最优子结构性质可知:从公式(1)可以看出,该问题类似一个排列问题,求N个作业的最优调度问题,利用其子结构性质,对集合中的每一个作业进行试调度,在所有的试调度中,取其中加工时间最短的作业做为选择方案。

00算法笔记记录——回溯法批作业调度问题及符号三角形问题.doc

00算法笔记记录——回溯法批作业调度问题及符号三角形问题.doc

1、批作度(1)问题描述定 n 个作的集合 {J1,J2, ⋯,Jn}。

每个作必先由机器 1 理,然后由机器 2 理。

作 Ji 需要机器 j 的理 tji。

于一个确定的作度, Fji 是作 i 在机器 j 上完成理的。

所有作在机器 2 上完成理的和称作度的完成和。

批处理作业调度问题要求对于给定的 n 个作业,制定最佳作业调度方案,使其完成时间和达到最小。

例: n=3 ,考以下例:3 个作的 6 种可能的度方案是 1,2,3 ;1,3,2 ; 2,1,3 ;2,3,1 ;3,1,2 ;3,2,1 ;它所相的完成和分是19,18,20,21,19 ,19。

易,最佳度方案是1,3,2 ,其完成和18。

(2)算法设计批理作度要从 n 个作的所有排列中找出具有最小完成和的作度,所以如,批理作度的解空是一排列树。

按照回溯法搜索排列的算法框架,开始 x=[1,2, ⋯⋯n]是所的 n 个作,相的排列由 x[1:n] 的所有排列构成。

算法具体代如下:[cpp]view plain copy1.#include "stdafx.h"2.#include <iostream>ing namespace std;4.5.class Flowshop6.{7.friend int Flow( int **M, int n, int bestx[]);8.private :9. void Backtrack( int i);10.11. int **M, // 各作业所需的处理时间12. *x, // 当前作业调度13. *bestx, // 当前最优作业调度14.15. *f2, // 机器 2 完成处理时间16. f1, // 机器 1 完成处理时间17. f, // 完成时间和18.19. bestf, // 当前最优值20. n; // 作业数21.};22.23. int Flow( int **M, int n, int bestx[]);24.25. template < class Type>26. inline void S &a, Type &b);27.28.int main()29.{30.int n=3,bf;31.int M1[4][3]={{0,0,0},{0,2,1},{0,3,1},{0,2,3}};32.33.int **M= new int *[n+1];34.35.for ( int i=0;i<=n;i++)36.{37.M[i]=new int[3];38.}39.cout<<"M(i,j) 值如下: " <<endl;40.41.for ( int i=0;i<=n;i++)42.{43.for ( int j=0;j<3;j++)44.{45.M[i][j]=M1[i][j];46.}47.}48.49.int bestx[4];50.for ( int i=1;i<=n;i++)51.{52.53.54.55. cout<< "(" ;for ( int j=1;j<3;j++)cout<<M[i][j]<< " " ; cout<< ")" ;56.}57.58.bf=Flow(M,n,bestx);59.60.for ( int i=0;i<=n;i++)61.{62.delete[]M[i];63.}64.delete []M;65.66.M=0;67.68.cout<<endl<<" 最优值是: " <<bf<<endl;69.cout<<" 最优调度是: " ;70.71.for ( int i=1;i<=n;i++)72.{73.cout<<bestx[i]<<" " ;74.}75.cout<<endl;76.return 0;77.}78.79. void Flowshop::Backtrack(int i)80.{81.if (i>n)82.{83.for ( int j=1; j<=n; j++)84.{85.bestx[j] = x[j];86.}87.bestf = f;88.}89.else90.{91.for ( int j = i; j <= n; j++)92.{93.f1+=M[x[j]][1];94.// 机器 2 执行的是机器 1 已完成的作业,所以是i-195.f2[i]=((f2[i-1]>f1)?f2[i-1]:f1)+M[x[j]][2];96.97.f+=f2[i];98.if (f < bestf)// 剪枝99.{100. Swap(x[i], x[j]);101. Backtrack(i+1);102. Swap(x[i], x[j]);103.}104.f1-=M[x[j]][1];105.f-=f2[i];106.}107.}108.}109.110. int Flow( int **M, int n, int bestx[])111.{112.int ub=30000;113.114.Flowshop X;115.X.n=n;116. X.x= new int [n+1];117. X.f2= new int [n+1];118.119.X.M=M;120.X.bestx=bestx;121.X.bestf=ub;122.123.X.f1=0;124.X.f=0;125.126.for ( int i=0;i<=n;i++)127.{128.X.f2[i]=0,X.x[i]=i;129.}130.X.Backtrack(1);131.delete []X.x;132.delete []X.f2;133.return X.bestf;134.}135.136.template < class Type>137. inline void S &a, Type &b)138.{139.Type temp=a;140.a=b;141.b=temp;142.}由于算法 Backtrack 在每一个节点处耗费O(1) 计算时间,故在最坏情况下,整个算法计算时间复杂性为O(n!) 。

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

1、批作业调度问题(1)问题描述给定n个作业的集合{J1,J2,…,Jn}。

每个作业必须先由机器1处理,然后由机器2处理。

作业Ji需要机器j的处理时间为tji。

对于一个确定的作业调度,设Fji是作业i在机器j上完成处理的时间。

所有作业在机器2上完成处理的时间和称为该作业调度的完成时间和。

批处理作业调度问题要求对于给定的n个作业,制定最佳作业调度方案,使其完成时间和达到最小。

例:设n=3,考虑以下实例:这3个作业的6种可能的调度方案是1,2,3;1,3,2;2,1,3;2,3,1;3,1,2;3,2,1;它们所相应的完成时间和分别是19,18,20,21,19,19。

易见,最佳调度方案是1,3,2,其完成时间和为18。

(2)算法设计批处理作业调度问题要从n个作业的所有排列中找出具有最小完成时间和的作业调度,所以如图,批处理作业调度问题的解空间是一颗排列树。

按照回溯法搜索排列树的算法框架,设开始时x=[1,2,……n]是所给的n个作业,则相应的排列树由x[1:n]的所有排列构成。

算法具体代码如下:[cpp]view plain copy1.#include "stdafx.h"2.#include <iostream>ing namespace std;4.5.class Flowshop6.{7.friend int Flow(int **M,int n,int bestx[]);8.private:9.void Backtrack(int i);10.11.int **M, // 各作业所需的处理时间12. *x, // 当前作业调度13. *bestx, // 当前最优作业调度14.15. *f2, // 机器2完成处理时间16. f1, // 机器1完成处理时间17. f, // 完成时间和18.19. bestf, // 当前最优值20. n; // 作业数21. };22.23.int Flow(int **M,int n,int bestx[]);24.25.template <class Type>26.inline void S &a, Type &b);27.28.int main()29.{30.int n=3,bf;31.int M1[4][3]={{0,0,0},{0,2,1},{0,3,1},{0,2,3}};32.33.int **M=new int*[n+1];34.35.for(int i=0;i<=n;i++)36. {37. M[i]=new int[3];38. }39. cout<<"M(i,j)值如下:"<<endl;40.41.for(int i=0;i<=n;i++)42. {43.for(int j=0;j<3;j++)44. {45. M[i][j]=M1[i][j];46. }47. }48.49.int bestx[4];50.for(int i=1;i<=n;i++)51. {52. cout<<"(";53.for(int j=1;j<3;j++)54. cout<<M[i][j]<<" ";55. cout<<")";56. }57.58. bf=Flow(M,n,bestx);59.60.for(int i=0;i<=n;i++)61. {62.delete []M[i];63. }64.delete []M;65.66. M=0;67.68. cout<<endl<<"最优值是:"<<bf<<endl;69. cout<<"最优调度是:";70.71.for(int i=1;i<=n;i++)72. {73. cout<<bestx[i]<<" ";74. }75. cout<<endl;76.return 0;77.}78.79.void Flowshop::Backtrack(int i)80.{81.if (i>n)82. {83.for (int j=1; j<=n; j++)84. {85. bestx[j] = x[j];86. }87. bestf = f;88. }89.else90. {91.for (int j = i; j <= n; j++)92. {93. f1+=M[x[j]][1];94.//机器2执行的是机器1已完成的作业,所以是i-195. f2[i]=((f2[i-1]>f1)?f2[i-1]:f1)+M[x[j]][2];96.97. f+=f2[i];98.if (f < bestf)//剪枝99. {100. Swap(x[i], x[j]); 101. Backtrack(i+1); 102. Swap(x[i], x[j]); 103. }104. f1-=M[x[j]][1];105. f-=f2[i];106. }107. }108.}109.110.int Flow(int **M,int n,int bestx[]) 111.{112.int ub=30000;113.114. Flowshop X;115. X.n=n;116. X.x=new int[n+1];117. X.f2=new int[n+1];118.119. X.M=M;120. X.bestx=bestx;121. X.bestf=ub;122.123. X.f1=0;124. X.f=0;125.126.for(int i=0;i<=n;i++)127. {128. X.f2[i]=0,X.x[i]=i;129. }130. X.Backtrack(1);131.delete []X.x;132.delete []X.f2;133.return X.bestf;134.}135.136.template <class Type>137.inline void S &a, Type &b)138.{139. Type temp=a;140. a=b;141. b=temp;142.}由于算法Backtrack在每一个节点处耗费O(1)计算时间,故在最坏情况下,整个算法计算时间复杂性为O(n!)。

程序运行结果如下:2、符号三角形问题(1)问题描速下图是由14个“+”和14个“-”组成的符号三角形。

2个同号下面都是“+”,2个异号下面都是“-”。

在一般情况下,符号三角形的第一行有n个符号。

符号三角形问题要求对于给定的n,计算有多少个不同的符号三角形,使其所含的“+”和“-”的个数相同。

(2)算法设计解向量:用n元组x[1:n]表示符号三角形的第一行。

当x[i]=1时表示符号三角形第一行的第i个符号为"+";当i=0时,表示符号三角形第一行的第i个符号为"-";1<=x<=n。

由于x[i]是二值的,所以可以用一棵完全二叉树来表示解空间。

可行性约束函数:在符号三角形的第一行前i个符号x[1:i]确定后,就确定了一个由i(i+1)/2个符号组成的符号三角形。

下一步确定x[i+1]的值后,只要在前面已确定的符号三角形的右边加一条边,就可以扩展为x[1:i+1]所相应的符号三角形。

最终由x[1:n]所确定的符号三角形中包含"+"号个数与"-"个数同为n(n+1)/4。

因此,当前符号三角形所包含的“+”个数与“-”个数均不超过n*(n+1)/4 。

无解的判断:对于给定的n,当n*(n+1)/2为奇数时,显然不存在包含的"+"号个数与"-"号个数相同的符号三角形。

此时,可以通过简单的判断加以处理。

程序的具体代码如下:[cpp]view plain copy1.#include "stdafx.h"2.#include <iostream>ing namespace std;4.5.class Triangle6.{7.friend int Compute(int);8.private:9.void Backtrack(int i);10.int n, //第一行的符号个数11. half, //n*(n+1)/412. count, //当前"+"号个数13. **p; //符号三角矩阵14.long sum; //已找到的符号三角形数15.};16.17.int Compute(int n);18.19.int main()20.{21.for(int n=1;n<=10;n++)22. {23. cout<<"n="<<n<<"时,共有"<<Compute(n);24. cout<<"个不同的符号三角形。

"<<endl;25. }26.return 0;27.}28.29.void Triangle::Backtrack(int t)30.{31.if ((count>half)||(t*(t-1)/2-count>half))32. {33.return;34. }35.36.if (t>n)37. {38. sum++;39. }40.else41. {42.for (int i=0;i<2;i++)43. {44. p[1][t]=i;//第一行符号45. count+=i;//当前"+"号个数46.47.for(int j=2;j<=t;j++)48. {49. p[j][t-j+1]=p[j-1][t-j+1]^p[j-1][t-j+2];50. count+=p[j][t-j+1];51. }52. Backtrack(t+1);53.for (int j=2;j<=t;j++)54. {55. count-=p[j][t-j+1];56. }57. count-=i;58. }59. }60.}61.62.int Compute(int n)63.{64. Triangle X;65. X.n=n;66. X.count=0;67. X.sum=0;68.69. X.half=n*(n+1)/2;70.if(X.half%2==1)return 0;71. X.half=X.half/2;72.73.int**p=new int*[n+1];74.75.for(int i=0;i<=n;i++)76. {77. p[i]=new int[n+1];78. }79.80.for(int i=0;i<=n;i++)81. {82.for(int j=0;j<=n;j++)83. {84. p[i][j]=0;85. }86. }87.88. X.p=p;89. X.Backtrack(1);90.for(int i=0;i<=n;i++)91. {92.delete []p[i];93. }94.delete []p;95. p=0;96.return X.sum;97.}计算可行性约束需要O(n)时间,在最坏情况下有O(2^n)个结点需要计算可行性约束,故解符号三角形问题的回溯算法所需的计算时间为O(n2^n)。

相关文档
最新文档