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记录相应的当前最佳作业调度。

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;}。

作业调度问题.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 的下一个儿子(如果存在)。

调度问题中的算法

调度问题中的算法

调度问题中的算法作者:***来源:《中国信息技术教育》2020年第11期说到“调度”,人们往往会想到交通运输部门的运行安排,也会想到企业中复杂的生产任务安排。

其实,日常生活中也经常面临着多个事项需要合理安排;只不过任务数不大,也不涉及明显的经济指标限制,人们凭经验就足以应付,很少会联想到“算法”。

当需要解决的任务数增加,且包含相互依赖关系时,算法可以帮助我们顺利有效地完成任务。

● 单纯依赖关系约束下的任务调度我们从仅考虑任务间的依赖约束开始。

如果任务X只能在另外某个任务Y完成后才能开始,我们就说X依赖Y。

下面来看一个简单的例子。

同学们打算在教室里组织一场联欢活动,还准备自己动手包饺子。

他们拟定了一张准备工作任务表,包含所有任务事项、每项任务耗时、任务间依赖关系(注意:只需列出直接依赖关系,而间接依赖关系自然地隐含在其中)。

管理上通常将这些任务的集合称为一个“项目”。

任务列表见表1。

有些任务之间没有依赖关系,执行顺序无关紧要,如果有多个执行者,这样的任务就可以并行。

这里说的“调度”,就是要给每项任务分配一个不同的序号,表示它们执行的顺序,满足:如果任务X依赖任务Y,则X的序号就要大于Y的序号;如果两个任务之间没有依赖关系,则对它们的序号关系没有要求。

从数学上看,原来所有任务间的依赖关系确定了一个“偏序”,即并非任意两个任务都必须“有先后”(称为“可比”)。

调度就是要在此基础上生成一个“全序”,即任何两个任务皆“可比”,对任意两个原来就“可比”的任务,新关系与原关系保持一致。

换句话说,如果按照这个序号串行执行,一定满足原来要求的依赖关系。

这个问题被称为“拓扑排序”问题。

读者应该注意到,如果只要解决拓扑排序问题,我们并不需要考虑上述例子中每项子任务的耗时。

我们可以建立一个有向图模型。

图中每个节点表示一个任务,节点X和Y之间存在从X 到Y的有向边(X→Y)当且仅当对应的任务X直接依赖于任务Y。

上述例子的图模型如下页图1所示。

第五章 回溯法

第五章  回溯法

• Cr=C=30,V=0
C为容量,Cr为剩余空间,V为价值。 • A为唯一活结点,也是当前扩展结点。
H D 1 0 I 1
1 B 0 E 1 0 J K
A
0 C 1 F 1 0 L M N 0 G 1 0 O
5.1 回溯法的算法框架
• n=3, C=30, w={16,15,15}, v={45,25,25}
理论上
寻找问题的解的一种可靠的方法是首先列出所有候选解,然后依次检查每一个, 在检查完所有或部分候选解后,即可找到所需要的解。
但是
当候选解数量有限并且通过检查所有或部分候选解能够得到所需解时,上述方
法是可行的。
若候选解的数量非常大(指数级,大数阶乘),即便采用最快的计算机也只能 解决规模很小的问题。
显约束
对分量xi的取值限定。
隐约束 为满足问题的解而对不同分量之间施加的约束。
5.1 回溯法的算法框架
解空间(Solution Space)
对于问题的一个实例,解向量满足显式约束条件的所有多元组,构成了该 实例的一个解空间。 注意:同一问题可有多种表示,有些表示更简单,所需状态空间更小(存储 量少,搜索方法简单)。
回溯法引言
以深度优先的方式系统地搜索问题的解的算法称为回溯法 使用场合
对于许多问题,当需要找出它的解的集合或者要求回答什么解是满足某些
约束条件的最佳解时,往往要使用回溯法。 这种方法适用于解一些组合数相当大的问题,具有“通用解题法”之称。 回溯法的基本做法 是搜索,或是一种组织得井井有条的,能避免不必要搜索的穷举式搜索法。
一个正在产生儿子的结点称为扩展结点
活结点(L-结点,Live Node)
一个自身已生成但其儿子还没有全部生成的节点称做活结点

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

算法设计与分析课件--回溯法-作业调度问题
❖ 计算任务由计算机的中央处理器完成,打印输出任务 由打印机完成。
❖ 计算机处理器是机器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
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

122. 123. 124.
X.f1=0; X.f=0;
125. 126. 127. 128. 129. 130. 131. 132. 133.
for(int i=0;i<=n;i++) {
X.f2[i]=0,X.x[i]=i; } X.Backtrack(1); delete []X.x; delete []X.f2; return X.bestf;
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. int bestx[4];
49. for(int i=1;i<=n;i++)
63.
}
64.
delete []M;
65.
66.
M=0;
67.
68.
cout<<endl<<"最优值是:"<<bf<<endl;
69.
cout<<"最优调度是:";
70.
7Байду номын сангаас.
for(int i=1;i<=n;i++)
72.
{
73.
cout<<bestx[i]<<" ";
74.
}
cout<<endl; 75.
批处理作业调度问题要求对于给定的 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。
111. {
112.
int ub=30000;
113.
114.
Flowshop X;
115. 116. 117.
X.n=n; X.x=new int[n+1]; X.f2=new int[n+1];
118. 119. 120. 121.
X.M=M; X.bestx=bestx; X.bestf=ub;
134. }
135. 136. template <class Type>
137. inline void Swap(Type &a, Type &b)
return 0; 76.
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. else
98.
if (f < bestf)//剪枝
99.
{
100.
Swap(x[i], x[j]);
101.
Backtrack(i+1);
102.
Swap(x[i], x[j]);
103. 104. 105. 106. 107.
} f1-=M[x[j]][1]; f-=f2[i]; } }
108. }
109. 110. int Flow(int **M,int n,int bestx[])
50. {
51. cout<<"(";
52. for(int j=1;j<3;j++)
53. cout<<M[i][j]<<" ";
54. cout<<")";
55.
56. }
57.
58.
bf=Flow(M,n,bestx);
59.
60.
for(int i=0;i<=n;i++)
61.
{
62.
delete []M[i];
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);
(2)算法设计
批处理作业调度问题要从 n 个作业的所有排列中找出具有最小完成 时间和的作业调度,所以如图,批处理作业调度问题的解空间是一颗 排列树。按照回溯法搜索排列树的算法框架,设开始时 x=[1,2,……n]是 所给的 n 个作业,则相应的排列树由 x[1:n]的所有排列构成。
算法具体代码如下:
[cpp] view plain copy
1. #include "stdafx.h"
2. #include <iostream>
3. using namespace std;
4. 5. class Flowshop
6. {
7.
friend int Flow(int **M,int n,int bestx[]);
90. {
91.
for (int j = i; j <= n; j++)
92.
{
93.
f1+=M[x[j]][1];
94.
//机器 2 执行的是机器 1 已完成的作业,所以是 i-1
95.
f2[i]=((f2[i-1]>f1)?f2[i-1]:f1)+M[x[j]][2];
96.
97.
f+=f2[i];
1、批作业调度问题
(1)问题描述
给定 n 个作业的集合{J1,J2,…,Jn}。每个作业必须先由机器 1 处 理,然后由机器 2 处理。作业 Ji 需要机器 j 的处理时间为 tji。对于一 个确定的作业调度,设 Fji 是作业 i 在机器 j 上完成处理的时间。所有 作业在机器 2 上完成处理的时间和称为该作业调度的完成时间和。
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];
相关文档
最新文档